[ossim] 01/04: New upstream version 2.2.2

Bas Couwenberg sebastic at debian.org
Wed Feb 7 18:09:17 UTC 2018


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository ossim.

commit 851b6bc21e8baf2d78c257e580f29e61cd9653a1
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Feb 7 18:40:59 2018 +0100

    New upstream version 2.2.2
---
 CMakeLists.txt                                     |  10 +
 cmake/CMakeLists.txt                               |  10 +-
 cmake/scripts/ossim-cmake-config.sh                |  17 +-
 include/ossim/base/JsonInterface.h                 |  31 +
 include/ossim/base/ossimKeywordlist.h              |  27 +-
 include/ossim/imaging/ossimWriter.h                | 111 ++-
 include/ossim/init/JsonConfig.h                    | 184 +++++
 include/ossim/projection/ossimImageViewTransform.h |   8 +-
 include/ossim/projection/ossimRpcSolver.h          |   7 +-
 include/ossim/projection/ossimSensorModel.h        |   2 +-
 include/ossim/projection/ossimSensorModelTuple.h   |   2 +-
 include/ossim/reg/GroundControlPoint.h             |  83 +++
 include/ossim/reg/Image.h                          |  85 +++
 include/ossim/reg/PhotoBlock.h                     |  99 +++
 include/ossim/reg/TiePoint.h                       | 126 ++++
 include/ossim/util/ossimTool.h                     |  16 +-
 scripts/archive.sh                                 |   2 +-
 scripts/build.sh                                   |   7 +-
 scripts/env.sh                                     |   2 +-
 scripts/install.sh                                 |   2 +-
 share/ossim/templates/ossim_preferences_template   |   5 +-
 src/CMakeLists.txt                                 |   9 +-
 src/base/ossimKeywordlist.cpp                      | 425 +++++++++++-
 src/imaging/ossimImageRenderer.cpp                 |  27 +-
 src/imaging/ossimImageWriterFactory.cpp            |   5 +-
 src/imaging/ossimWriter.cpp                        | 746 +++++++++++++++------
 src/init/JsonConfig.cpp                            | 467 +++++++++++++
 src/projection/ossimImageViewTransform.cpp         |  15 +
 src/projection/ossimRpcModel.cpp                   |   3 +-
 src/projection/ossimSensorModel.cpp                |   4 +-
 src/projection/ossimSensorModelTuple.cpp           | 197 +++---
 src/reg/GroundControlPoint.cpp                     | 121 ++++
 src/reg/Image.cpp                                  | 115 ++++
 src/reg/PhotoBlock.cpp                             | 183 +++++
 src/reg/TiePoint.cpp                               | 243 +++++++
 src/support_data/ossimQuickbirdRpcHeader.cpp       |  12 +
 src/util/ossimTool.cpp                             |   5 -
 37 files changed, 3051 insertions(+), 362 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c3a4bb..f619f1b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -103,6 +103,16 @@ else( TIFF_FOUND )
    message( FATAL_ERROR "Could not find required tiff package!" )
 endif( TIFF_FOUND )
 
+# JSONCPP - Required:
+find_package( JsonCpp )
+if( JSONCPP_FOUND )
+   include_directories( ${JSONCPP_INCLUDE_DIR} )
+   set( ossimDependentLibs ${ossimDependentLibs} ${JSONCPP_LIBRARY} )
+   message("Found JsonCpp" )
+else( JSONCPP_FOUND )
+   message( FATAL_ERROR "Could not find required JsonCpp package!" )
+endif( JSONCPP_FOUND )
+
 # This caused a core dump on ossim executables running in jenins pipeline (ossim-test-dev)
 if (CMAKE_SYSTEM_NAME MATCHES "Linux")
   find_library( DL_LIBRARY dl )
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 1dd79f1..91a2e95 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -122,8 +122,8 @@ IF(BUILD_OSSIM_VIDEO AND EXISTS ${OSSIM_DEV_HOME}/ossim-video)
   add_subdirectory(${OSSIM_DEV_HOME}/ossim-video ${CMAKE_CURRENT_BINARY_DIR}/ossim-video)
 ENDIF()
 
-IF(BUILD_ISA_PLUGIN AND EXISTS ${OSSIM_DEV_HOME}/ossim-isa-plugin)
-  add_subdirectory(${OSSIM_DEV_HOME}/ossim-isa-plugin ${CMAKE_CURRENT_BINARY_DIR}/ossim-isa-plugin)
+IF(BUILD_MSP_PLUGIN AND EXISTS ${OSSIM_DEV_HOME}/ossim-msp-plugin)
+  add_subdirectory(${OSSIM_DEV_HOME}/ossim-msp-plugin ${CMAKE_CURRENT_BINARY_DIR}/ossim-msp-plugin)
 ENDIF()
 
 IF(BUILD_CSM_PLUGIN AND EXISTS ${OSSIM_DEV_HOME}/ossim-csm-plugin)
@@ -188,6 +188,10 @@ IF(BUILD_DSMG AND EXISTS ${OSSIM_DEV_HOME}/ossim-dsmg)
   add_subdirectory(${OSSIM_DEV_HOME}/ossim-dsmg ${CMAKE_CURRENT_BINARY_DIR}/ossim-dsmg)
 ENDIF()
 
+IF(BUILD_OSSIM_ISA AND EXISTS ${OSSIM_DEV_HOME}/ossim-isa)
+  add_subdirectory(${OSSIM_DEV_HOME}/ossim-isa ${CMAKE_CURRENT_BINARY_DIR}/ossim-isa)
+ENDIF()
+
 
 ############################## Doxygen installation for current ossim core module ###########################################
 FIND_PACKAGE(Doxygen)
@@ -365,6 +369,6 @@ MESSAGE( STATUS "BUILD_OSSIM_WMS                 = ${BUILD_OSSIM_WMS}" )
 MESSAGE( STATUS "BUILD_LIBRARY_DIR               = ${BUILD_LIBRARY_DIR}" )
 MESSAGE( STATUS "BUILD_RUNTIME_DIR               = ${BUILD_RUNTIME_DIR}" )
 MESSAGE( STATUS "BUILD_DSMG                      = ${BUILD_DSMG}" )
-MESSAGE( STATUS "BUILD_ISA_PLUGIN                = ${BUILD_ISA_PLUGIN}" )
+MESSAGE( STATUS "BUILD_MSP_PLUGIN                = ${BUILD_MSP_PLUGIN}" )
 MESSAGE( STATUS "BUILD_CSM_PLUGIN                = ${BUILD_CSM_PLUGIN}" )
 MESSAGE( STATUS "Use OSSIM_BUILD_ADDITIONAL_DIRECTORIES to add other cmake builds." )
diff --git a/cmake/scripts/ossim-cmake-config.sh b/cmake/scripts/ossim-cmake-config.sh
index 799ed18..1944e05 100755
--- a/cmake/scripts/ossim-cmake-config.sh
+++ b/cmake/scripts/ossim-cmake-config.sh
@@ -7,7 +7,7 @@
 # DO NOT RELOCATE THIS SCRIPT. Its location is used to resolve relative
 # directory paths.
 #
-# Usage: <this_script_name> [<build_type>] 
+# Usage: <this_script_name> [<build_type>]
 #
 # where the optional <build_type> is one of the following literals 
 # (case-insensitive):
@@ -16,11 +16,11 @@
 #     "debug", 
 #     "relWithDebInfo", 
 #     "minSizeRel",
-#     "eclipse"
+#     "eclipse" 
 #
 # If a build type = "eclipse" is specified, cmake will generate a Debug
 # build environment along with Eclipse CDT4 project files (in the build
-# directory) for importing as existing project.
+# directory) for importing as existing project. 
 #
 # Instructions: Run this script to build the repository. This script can be
 # run from any directory, but will assume a default relative directory
@@ -147,6 +147,9 @@ if [ -z $BUILD_OSSIM_ISA ] ; then
 fi
 
 # Plugins:
+if [ -z $BUILD_ATP_PLUGIN ]; then
+  BUILD_ATP_PLUGIN=OFF
+fi
 if [ -z $BUILD_CNES_PLUGIN ]; then
   BUILD_CNES_PLUGIN=OFF
 fi
@@ -165,8 +168,8 @@ fi
 if [ -z $BUILD_HDF5_PLUGIN ]; then
   BUILD_HDF5_PLUGIN=OFF
 fi
-if [ -z $BUILD_ISA_PLUGIN ]; then
-  BUILD_ISA_PLUGIN=OFF
+if [ -z $BUILD_MSP_PLUGIN ]; then
+  BUILD_MSP_PLUGIN=OFF
 fi
 if [ -z $BUILD_KAKADU_PLUGIN ]; then
   BUILD_KAKADU_PLUGIN=OFF
@@ -251,10 +254,10 @@ cmake -G "$CMAKE_G_ARG" \
 -DCMAKE_OSX_ARCHITECTURES="x86_64" \
 -DCMAKE_OSX_SYSROOT=$CMAKE_OSX_SYSROOT \
 -DCMAKE_OSX_DEPLOYMENT_TARGET=$CMAKE_OSX_DEPLOYMENT_TARGET \
--DCMAKE_ECLIPSE_VERSION=$CMAKE_ECLIPSE_VERSION \
 -DBUILD_OSSIM_FRAMEWORKS=${BUILD_OSSIM_FRAMEWORKS} \
 -DBUILD_OMS=$BUILD_OMS \
 -DBUILD_OSSIM_PLANET_GUI=${BUILD_OSSIM_PLANET_GUI} \
+-DBUILD_ATP_PLUGIN=$BUILD_ATP_PLUGIN \
 -DBUILD_CNES_PLUGIN=$BUILD_CNES_PLUGIN \
 -DBUILD_CSM_PLUGIN=$BUILD_CSM_PLUGIN \
 -DBUILD_DSMG=$BUILD_DSMG \
@@ -263,7 +266,7 @@ cmake -G "$CMAKE_G_ARG" \
 -DBUILD_GEOPDF_PLUGIN=$BUILD_GEOPDF_PLUGIN \
 -DBUILD_GDAL_PLUGIN=$BUILD_GDAL_PLUGIN \
 -DBUILD_HDF5_PLUGIN=$BUILD_HDF5_PLUGIN \
--DBUILD_ISA_PLUGIN=$BUILD_ISA_PLUGIN \
+-DBUILD_MSP_PLUGIN=$BUILD_MSP_PLUGIN \
 -DBUILD_KAKADU_PLUGIN=$BUILD_KAKADU_PLUGIN \
 -DBUILD_JPEG12_PLUGIN=$BUILD_JPEG12_PLUGIN \
 -DKAKADU_ROOT_SRC=$KAKADU_ROOT_SRC \
diff --git a/include/ossim/base/JsonInterface.h b/include/ossim/base/JsonInterface.h
new file mode 100644
index 0000000..43c368d
--- /dev/null
+++ b/include/ossim/base/JsonInterface.h
@@ -0,0 +1,31 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+#ifndef JsonInterface_HEADER
+#define JsonInterface_HEADER 1
+
+#include <json/json.h>
+
+namespace ossim {
+
+/**
+ * Pure virtual interface for classes implementing JSON-based load/save state..
+ * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+ * for JSON formats used.
+ */
+class JsonInterface
+{
+public:
+   JsonInterface() {}
+   virtual ~JsonInterface() {}
+
+   virtual void loadJSON(const Json::Value& jsonNode) = 0;
+   virtual void saveJSON(Json::Value& jsonNode) const = 0;
+
+};
+
+}
+#endif
diff --git a/include/ossim/base/ossimKeywordlist.h b/include/ossim/base/ossimKeywordlist.h
index 4ebd618..553eb8a 100644
--- a/include/ossim/base/ossimKeywordlist.h
+++ b/include/ossim/base/ossimKeywordlist.h
@@ -339,7 +339,7 @@ public:
     *  or an empty string if the key was not found.
     *  @param key e.g. "number_line"
     *  @param prefix e..g "image0."
-    *  @return Reference to string.  This will be emptry if not found or
+    *  @return Reference to string.  This will be empty if not found or
     *  if value is empty.
     */
    const std::string& findKey(const std::string& key) const;
@@ -390,6 +390,20 @@ public:
 
    virtual void writeToStream(std::ostream &out)const;
 
+   /**
+    * Outputs in xml format.
+    * @param out Stream to write to.
+    * @param rootTag name of the root XML element/tag
+    */
+   void toXML(std::ostream &out, const std::string& rootTag="info")const;
+   
+   /**
+    * Outputs in json format.
+    * @param out Stream to write to.
+    * @param rootTag name of the root json element/tag
+    */
+   void toJSON(std::ostream &out, const std::string& rootTag="info")const;
+   
    virtual std::ostream& print(std::ostream& os) const;
    OSSIMDLLEXPORT friend std::ostream& operator<<(std::ostream& os,
                                                   const ossimKeywordlist& kwl);
@@ -566,6 +580,17 @@ protected:
    KeywordMap::iterator getMapEntry(const ossimString& key);
    KeywordMap::iterator getMapEntry(const char* key);
 
+   // For toXML method lifted from oms::DataInfo.
+   bool isSpecialXmlCharacters(const ossimString& value) const;
+   bool isValidTag(const std::string& value)const;
+   void replaceSpecialCharacters(ossimString& value)const;
+
+   /**
+    * @return true if a == b, false if not.
+    */
+   bool isSame( const std::vector<ossimString>& a,
+                const std::vector<ossimString>& b ) const;
+
    KeywordMap               m_map;
    char                     m_delimiter;
 
diff --git a/include/ossim/imaging/ossimWriter.h b/include/ossim/imaging/ossimWriter.h
index 5880b9c..062d6d5 100644
--- a/include/ossim/imaging/ossimWriter.h
+++ b/include/ossim/imaging/ossimWriter.h
@@ -2,8 +2,6 @@
 //
 // License: MIT
 // 
-// See LICENSE.txt file in the top level directory for more details.
-//
 // Author:  David Burken
 //
 // Description: Generic image writer class.
@@ -14,10 +12,14 @@
 #define ossimWriter_HEADER 1
 
 #include <ossim/base/ossimConstants.h>
+#include <ossim/base/ossimIpt.h>
 #include <ossim/imaging/ossimImageFileWriter.h>
 #include <iosfwd>
 #include <vector>
 
+class ossimKeywordlist;
+class ossimProperty;
+
 /**
  * @brief ossimWriter - Generic image writer.
  *
@@ -101,6 +103,56 @@ public:
     */
    virtual bool setOutputStream(std::ostream& str);
 
+   /**
+    * @brief Sets the output tile size for tiled formats.
+    * @param tileSize Must be a multiple of 16.
+    */
+   virtual void setTileSize(const ossimIpt& tileSize);
+
+   /**
+    * @brief Gets the tile size.
+    * @return Reference to tile size.
+    */
+   virtual const ossimIpt& getOutputTileSize() const;
+
+   /**
+    * @brief Saves the state of the object.
+    */
+   virtual bool saveState(ossimKeywordlist& kwl,
+                          const char* prefix=0)const;
+   
+   /**
+    * Method to the load (recreate) the state of an object from a keyword
+    * list.  Return true if ok or false on error.
+    */
+   virtual bool loadState(const ossimKeywordlist& kwl,
+                          const char* prefix=0);
+
+   /**
+    * Will set the property whose name matches the argument
+    * "property->getName()".
+    *
+    * @param property Object containing property to set.
+    */
+   virtual void setProperty(ossimRefPtr<ossimProperty> property);
+   
+   /**
+    * @param name Name of property to return.
+    * 
+    * @returns A pointer to a property object which matches "name".  Returns
+    * NULL if no match is found.
+    */
+   virtual ossimRefPtr<ossimProperty> getProperty(const ossimString& name) const;
+
+   /**
+    * Pushes this's names onto the list of property names.
+    *
+    * @param propertyNames array to add this's property names to.
+    */
+   virtual void getPropertyNames(std::vector<ossimString>& propertyNames) const;
+
+ 
+   
 protected:
    
    /**
@@ -110,7 +162,7 @@ protected:
    virtual bool writeFile();
 
 private:
-
+   
    /**
     * @brief Writes a tiled tiff band separate to stream.
     * @return true on success, false on error.
@@ -140,13 +192,9 @@ private:
     * @brief Writes tags TIFFTAG_MINSAMPLEVALUE(280) and
     * TIFFTAG_MAXSAMPLEVALUE(281).  Only written if scalar type is an unsigned
     * byte or short.
-    * @param minBands Array of min values from image write.
-    * @param maxBands Array of max values from image write.
     * @return true on success, false on error.
     */
-   bool writeMinMaxTiffTags( const std::vector<ossim_float64>& minBands,
-                             const std::vector<ossim_float64>& maxBands,
-                             std::streamoff& arrayWritePos  );
+   bool writeMinMaxTiffTags( std::streamoff& arrayWritePos  );
 
 
    /**
@@ -155,7 +203,9 @@ private:
     * unsigned byte or short.
     * @param minBands Array of min values from image write.
     * @param maxBands Array of max values from image write.
-    * @return true on success, false on error.
+    * @return true if tags are written, false if not.
+    * A false return is not necessarily an error, just means the
+    * tags were not written due to the scalar type.
     */
    bool writeSMinSMaxTiffTags( const std::vector<ossim_float64>& minBands,
                              const std::vector<ossim_float64>& maxBands,
@@ -199,9 +249,50 @@ private:
     * @return TIFF sample format or 0 if not mapped to a scalar type.
     */
    ossim_uint16 getTiffSampleFormat() const;
+
+   /**
+    *  @return true if the output type is tiled, false if not.
+    */
+   bool isTiled() const;
+
+   /**
+    * @return Value of options key: "align_tiles".
+    * If true, aligns tile addresses to 4096 boundary.
+    * default=true
+    */
+   bool getAlignTilesFlag() const;
+
+   /**
+    * @return Value of options key: "flush_tiles".
+    * If true, aligns tile addresses to block boundary.
+    * default=true
+    */
+   ossim_int64 getBlockSize() const;
+
+   /**
+    * @return Value of options key: "flush_tiles".
+    * If true, ostream::flush() is called after each tile write.
+    * default=true
+    */
+   bool getFlushTilesFlag() const;
+  
+   /**
+    * @return Value of options key: "include_blank_tiles".
+    * If true, empty/blank tiles will be written; if false, the tile will not
+    * be written, the tile offset and byte count will be set to zero.
+    * default=true (write blanks).
+    */
+   bool getWriteBlanksFlag() const;
+
+   bool needsMinMax() const;
   
    std::ostream* m_str;
-   bool          m_ownsStreamFlag; 
+   bool          m_ownsStreamFlag;
+
+   /** Hold all options. */
+   ossimRefPtr<ossimKeywordlist> m_kwl;
+   
+   ossimIpt      m_outputTileSize;
    
 }; // End: class ossimWriter
 
diff --git a/include/ossim/init/JsonConfig.h b/include/ossim/init/JsonConfig.h
new file mode 100644
index 0000000..f20e584
--- /dev/null
+++ b/include/ossim/init/JsonConfig.h
@@ -0,0 +1,184 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#pragma once
+
+#include <ostream>
+#include <ossim/plugin/ossimPluginConstants.h>
+#include <ossim/base/JsonInterface.h>
+#include <ossim/base/ossimFilename.h>
+#include <vector>
+#include <map>
+
+namespace ossim
+{
+// Forward decl defined after JsonParam
+class JsonParam;
+
+/**
+ * Base class for maintaining parameters affecting the runtime configuration of OSSIM executables.
+ * The state is imported and exported via JSON. There are default configuration files that should
+ * be part of the install, that are accessed by this class. Custom settings can also be loaded.
+ *
+ * There are two functionally equivalent forms for specifying parameters: long and short.
+ * Parameters are initially declared via the long form with descriptions and default values. These
+ * values must be supplied in default JSON files as part of the OSSIM install.
+ *
+ * Once the parameters are declared via the long form, the short form can be used to supply runtime
+ * overrides.
+ *
+ * The long form format is
+ *
+ *    {  "parameters": [
+ *          {
+ *             "name": "<param_name>",
+ *             "descr": "<param description",
+ *             "type": "string"|"float"|"uint"|"int"|"bool",
+ *             "value": <value>
+ *          }, ...
+ *       ]
+ *    }
+ *
+ * The short form is:
+ *
+ *    {  "parameters": [
+ *          "<param_name>": <value>, ...
+ *       ]
+ *    }
+ *
+ * The short form parameter is only accepted if it has previously been loaded via the long form so
+ * that the data type is known.
+ *
+ * Parameters are usually accessed knowing the data type ahead of time. For example, a string
+ * parameter is accessed as:
+ *
+ *    string paramVal = jsonConfig.getParameter("param_name").asSTring();
+ *
+ * If the parameter is not found, the special null-parameter is returned from getParameter(), and
+ * casting to a tye will return 0, false, or empty string.
+ */
+class OSSIM_DLL JsonConfig : public ossim::JsonInterface
+{
+public:
+   JsonConfig();
+
+   /** Default Ctor loads all default .json files in the share/ossim system dir */
+   JsonConfig(const ossimFilename& configFile);
+
+   //! Destructor
+   virtual ~JsonConfig();
+
+   //! Opens and parses JSON file. The "parameters" keyword is expected in the root node
+   bool open(const ossimFilename& configFile);
+
+   //! Reads the params controlling the process from the JSON node named "parameters".
+   virtual void loadJSON(const Json::Value& params_json_node);
+
+   //! Reads the params controlling the process from the JSON node named "parameters".
+   virtual void saveJSON(Json::Value& params_json_node) const;
+
+   //! Returns a parameter (might be a null parameter if paramName not found in the configuration.
+   JsonParam& getParameter(const char* paramName);
+
+   /** Adds parameter to the configuration. Any previous parameter of the same name is replaced. */
+   void setParameter(const JsonParam& p);
+
+   //! Convenience method returns TRUE if the currently set diagnostic level is <= level
+   bool diagnosticLevel(unsigned int level) const;
+
+   //! Outputs JSON to output stream provided.
+   friend std::ostream& operator<<(std::ostream& out, const JsonConfig& obj);
+
+   bool paramExists(const char* paramName) const;
+
+protected:
+   JsonConfig(const JsonConfig& /*hide_this*/) {}
+
+   bool getBoolValue(bool& rtn_val, const std::string& json_value) const;
+
+   std::map<std::string, JsonParam> m_paramsMap;
+   static JsonParam s_nullParam;
+};
+
+
+/**
+ * Represents a single configuration parameter. This class provides for packing and unpacking the
+ * parameter from JSON payload, and provides for handling all datatypes of parameters.
+ */
+class JsonParam
+{
+public:
+   enum ParamType {
+      UNASSIGNED=0,
+      BOOL=1,
+      INT=2,
+      UINT=3,
+      FLOAT=4,
+      STRING=5,
+      VECTOR=6
+   };
+
+   JsonParam() : _type(UNASSIGNED), _value(0) {}
+
+   JsonParam(const ossimString& argname,
+            const ossimString& arglabel,
+            const ossimString& argdescr,
+            ParamType   argparamType,
+            void* value);
+
+   JsonParam(const JsonParam& copy);
+
+   ~JsonParam() { resetValue(); }
+
+   /** Initializes from a JSON node. Return true if successful */
+   bool loadJSON(const Json::Value& json_node);
+
+   void saveJSON(Json::Value& json_node) const;
+
+   const ossimString& name() const { return _name; }
+   const ossimString& label() const { return _label; }
+   const ossimString& descr() const { return _descr; }
+   ParamType    type() const { return _type; }
+
+   bool isBool() const  {return (_type == BOOL); }
+   bool asBool() const;
+
+   bool isUint() const  {return (_type == UINT); }
+   unsigned int asUint() const;
+
+   bool isInt() const  {return (_type == INT);}
+   int  asInt() const;
+
+   bool isFloat() const {return (_type == FLOAT);}
+   double asFloat() const;
+
+   bool isString() const {return (_type == STRING);}
+   std::string asString() const;
+
+   bool isVector() const {return (_type == VECTOR);}
+   void asVector(std::vector<double>& v) const;
+
+   bool operator==(const JsonParam& p) const { return (p._name == _name); }
+
+   void setValue(const Json::Value& json_node);
+   void setValue(void* value);
+   void resetValue();
+
+   /** Outputs JSON to output stream provided */
+   friend std::ostream& operator<<(std::ostream& out, const JsonParam& obj);
+
+private:
+
+   ossimString _name;
+   ossimString _label;
+   ossimString _descr;
+   ParamType   _type;
+   void*       _value;
+};
+
+
+}
diff --git a/include/ossim/projection/ossimImageViewTransform.h b/include/ossim/projection/ossimImageViewTransform.h
index 393e61f..1f48d47 100644
--- a/include/ossim/projection/ossimImageViewTransform.h
+++ b/include/ossim/projection/ossimImageViewTransform.h
@@ -107,7 +107,13 @@ public:
   
   virtual ossimDpt getRoundTripErrorImage(const ossimDpt& imagePt)const;
 
-  virtual ossimDrect getImageToViewBounds(const ossimDrect& imageRect)const;
+  /** Computes the bounding rect in view space of the quad formed by the transformed image points
+   * of the input rect corners. */
+  virtual ossimDrect getImageToViewBounds(const ossimDrect& imageRect) const;
+
+  /** Computes the bounding rect in image space of the quad formed by the transformed view points
+   * of the input rect corners. */
+  virtual ossimDrect getViewToImageBounds(const ossimDrect& viewRect) const;
   
   virtual bool loadState(const ossimKeywordlist& kwl,
                          const char* prefix =0);
diff --git a/include/ossim/projection/ossimRpcSolver.h b/include/ossim/projection/ossimRpcSolver.h
index 046efb5..b8456cd 100644
--- a/include/ossim/projection/ossimRpcSolver.h
+++ b/include/ossim/projection/ossimRpcSolver.h
@@ -8,6 +8,7 @@
 #define ossimRpcSolver_HEADER
 
 #include <vector>
+#include <ossim/base/ossimConstants.h>
 #include <ossim/base/ossimRefPtr.h>
 #include <ossim/base/ossimDpt.h>
 #include <ossim/base/ossimGpt.h>
@@ -16,10 +17,8 @@
 #include <ossim/matrix/newmat.h>
 #include <ossim/projection/ossimRpcModel.h>
 #include <ossim/projection/ossimRpcProjection.h>
-
-class ossimProjection;
-class ossimImageGeometry;
-class ossimNitfRegisteredTag;
+#include <ossim/support_data/ossimNitfRegisteredTag.h>
+#include <ossim/imaging/ossimImageGeometry.h>
 
 /**
  * This currently only support Rational poilynomial B format.  This can be
diff --git a/include/ossim/projection/ossimSensorModel.h b/include/ossim/projection/ossimSensorModel.h
index 7360f9b..3ab2c62 100644
--- a/include/ossim/projection/ossimSensorModel.h
+++ b/include/ossim/projection/ossimSensorModel.h
@@ -253,7 +253,7 @@ public:
     */
    virtual ossimSensorModel::CovMatStatus getObsCovMat(
       const ossimDpt& ipos, NEWMAT::SymmetricMatrix& Cov,
-      const ossim_float64 defPointingSigma = 0.5);
+      const ossim_float64 defPointingSigma = 0.5) const;
 
    /**
     * @brief Implementation of pure virtual
diff --git a/include/ossim/projection/ossimSensorModelTuple.h b/include/ossim/projection/ossimSensorModelTuple.h
index c386981..7d7a253 100644
--- a/include/ossim/projection/ossimSensorModelTuple.h
+++ b/include/ossim/projection/ossimSensorModelTuple.h
@@ -143,7 +143,7 @@ public:
    void getRpcPqeInputs(ossimRpcPqeInputs& obj) const;
 
 private:
-   std::vector<ossimSensorModel*> theImages;
+   mutable std::vector<ossimRefPtr<ossimSensorModel> > theImages;
 
    ossim_int32    theNumImages;
    
diff --git a/include/ossim/reg/GroundControlPoint.h b/include/ossim/reg/GroundControlPoint.h
new file mode 100644
index 0000000..505888a
--- /dev/null
+++ b/include/ossim/reg/GroundControlPoint.h
@@ -0,0 +1,83 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#ifndef GroundControlPoint_HEADER
+#define GroundControlPoint_HEADER 1
+
+#include <ossim/base/JsonInterface.h>
+#include <ossim/base/ossimEcefPoint.h>
+#include <ossim/matrix/newmat.h>
+#include <memory>
+
+namespace ossim
+{
+/**
+ * Class for representing a ground control point.
+ * TODO: mplement cross-correlation between GCPs
+ */
+class GroundControlPoint : public ossim::JsonInterface,
+                           public std::enable_shared_from_this<GroundControlPoint>
+{
+public:
+
+   /**
+    * Creates new GCP from JSON object.
+    * The ground point (GCP) coordinates are specified in either ECF or geographic.
+    * The associated covariance must be in the same coordinate system. If correlations exist to
+    * other GCPs, those GCPs must share the same coordinate system.  TBD: Perhaps the GCP
+    * information, including coordinates, covariances and cross-covariances can be ingested prior
+    * and accessed from the database with only GCP ID. Id so, the remainder of this message is not
+    * needed.
+    *
+    * The JSON Format:
+    * {
+    *    "id": <string>,
+    *    "ecf": [ <X>, <Y>, <Z> ], OR
+    *    "geo": [ <lat>, <lon>, <hgt_msl> ],
+    *    "covariance": [ c11, c22, c33, c12, c13, c23 ],
+    *    "crossCovariances": [ (Can be excluded if no correlation information available)
+    *       {
+    *           "id": <string>, The other GCP’s ID
+    *           "crossCovariance": [ c11, c22, c33, c12, c13, c23 ]
+    *       }
+    *    ]
+    * }
+    *
+    */
+   GroundControlPoint(const Json::Value& image_json_node);
+
+   virtual ~GroundControlPoint();
+
+   const std::string& getId() const { return m_id; }
+   const ossimEcefPoint& getECF() const { return m_gcp; }
+
+   const NEWMAT::SymmetricMatrix& getCovariance() const {return m_covariance;}
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void loadJSON(const Json::Value& json);
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void saveJSON(Json::Value& json) const;
+
+private:
+   GroundControlPoint();
+
+   std::string m_id;
+   ossimEcefPoint m_gcp;
+   NEWMAT::SymmetricMatrix m_covariance; //> X, Y, Z (ECF)
+};
+
+typedef std::vector< std::shared_ptr<GroundControlPoint> > GcpList;
+
+} // end namespace ossimMsp
+#endif /* #ifndef GroundControlPoint_HEADER */
diff --git a/include/ossim/reg/Image.h b/include/ossim/reg/Image.h
new file mode 100644
index 0000000..0de6d12
--- /dev/null
+++ b/include/ossim/reg/Image.h
@@ -0,0 +1,85 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+#ifndef Image_HEADER
+#define Image_HEADER 1
+
+#include <map>
+#include <memory>
+#include <string>
+#include <ossim/base/ossimGpt.h>
+#include <ossim/base/ossimConstants.h>
+#include <ossim/base/ossimFilename.h>
+#include <ossim/matrix/newmat.h>
+#include <ossim/base/JsonInterface.h>
+#include <ossim/projection/ossimSensorModel.h>
+#include <string>
+
+namespace ossim
+{
+
+/**
+ * Class representing an Image as used by ossim-msp services.
+ */
+class OSSIM_DLL Image : public ossim::JsonInterface,
+                        public std::enable_shared_from_this<Image>
+{
+public:
+   static unsigned int UNASSIGNED_PHOTOBLOCK_INDEX;
+
+   Image(const std::string& imageId,
+         const std::string& filename,
+         const std::string& modelName="",
+         unsigned int entryIndex=0,
+         unsigned int band=1);
+
+   Image(const Json::Value& image_json_node);
+
+   ~Image();
+
+   std::string getImageId() const { return m_imageId; }
+   std::string getFilename() const { return m_filename; }
+   std::string getModelName() const { return m_modelName; }
+   unsigned int getEntryIndex() const { return m_entryIndex; }
+   unsigned int getActiveBand() const { return m_activeBand; }
+
+   void setImageId(const std::string& id) { m_imageId = id; }
+   void setFilename(const std::string& f) { m_filename = f; }
+   void setEntryIndex(unsigned int i) { m_entryIndex = i; }
+
+   /**
+    * Returns all available sensor model plugins and model names for this image:
+    * @param availableModels List of <plugin-name, model-name> pairs.
+    */
+    virtual void getAvailableModels(std::vector< pair<std::string, std::string> >& availableModels) const;
+
+    /**
+    * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+    * for JSON format used.
+    */
+    virtual void loadJSON(const Json::Value& json);
+
+    /**
+    * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+    * for JSON format used.
+    */
+    virtual void saveJSON(Json::Value& json) const;
+
+protected:
+   std::string m_imageId;
+   ossimFilename m_filename;
+   unsigned int m_entryIndex;
+   unsigned int m_activeBand;
+   std::string m_modelName;
+   std::vector< pair<std::string, std::string> > m_availableModel;
+   ossimRefPtr<ossimSensorModel> m_sensorModel;
+};
+
+typedef std::vector< std::shared_ptr<Image> > ImageList;
+
+} // End namespace ATP
+
+#endif
diff --git a/include/ossim/reg/PhotoBlock.h b/include/ossim/reg/PhotoBlock.h
new file mode 100644
index 0000000..9ab0fbd
--- /dev/null
+++ b/include/ossim/reg/PhotoBlock.h
@@ -0,0 +1,99 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+#ifndef PhotoBlock_HEADER
+#define PhotoBlock_HEADER 1
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <ossim/base/ossimConstants.h>
+#include <ossim/reg/GroundControlPoint.h>
+#include <ossim/reg/Image.h>
+#include <ossim/reg/TiePoint.h>
+#include <ossim/base/JsonInterface.h>
+
+namespace ossim
+{
+
+/**
+ * Class for representing MSP PhotoBlock.
+ */
+class PhotoBlock : public JsonInterface,
+                   public std::enable_shared_from_this<PhotoBlock>
+{
+public:
+   /**
+    * Initialize the photoblock from a prior saved session. If none found, assumes a new, blank
+    * session is being started.
+    */
+   PhotoBlock();
+   PhotoBlock(const Json::Value& pb_json_node);
+   PhotoBlock(const PhotoBlock& copyThis);
+
+   ~PhotoBlock();
+
+   PhotoBlock& operator=(const PhotoBlock& copythis);
+
+   std::shared_ptr<Image> getImage(const std::string& imageId);
+   std::shared_ptr<TiePoint> getTiePoint(unsigned int tpId);
+   std::shared_ptr<GroundControlPoint> getGroundPoint(const std::string& gpId);
+
+   ImageList&              getImageList()       { return m_imageList; }
+   TiePointList&           getTiePointList()    { return m_tiePointList; }
+   std::vector<std::shared_ptr<GroundControlPoint> >& getGroundPointList() { return m_gcpList; }
+
+   // TODO: Add of individual components not valid until proper management of the JCM can be
+   //       provided
+
+   /**
+    * Adds the image to the photoblock at last position. Sets the image's pb index member.
+    * @param images To be added to PB
+    * @return The PB index of the image in the photoblock.
+    */
+   unsigned int addImage(std::shared_ptr<Image> image);
+
+   /**
+    * Adds the image to the photoblock at last position. Sets the image's pb index member.
+    * @param images To be added to PB
+    * @return The PB index of the image in the photoblock.
+    */
+   unsigned int addGroundPoint(std::shared_ptr<GroundControlPoint> groundPoint);
+
+   /**
+    * Adds the tiepoint to the PB
+    * @param tiepoint To be added to PB
+    * @return The index of the TP in the photoblock (should be same as TP ID)
+    */
+   unsigned int addTiePoint(std::shared_ptr<TiePoint> tiepoint);
+
+   /**
+    * Adds the list of tiepoints to the PB
+    * @param tiepointList To be added to PB
+    */
+  void addTiePoints(TiePointList& tiepointList);
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void loadJSON(const Json::Value& json);
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void saveJSON(Json::Value& json) const;
+
+protected:
+   std::vector<std::shared_ptr<Image> > m_imageList;
+   std::vector<std::shared_ptr<TiePoint> > m_tiePointList;
+   std::vector<std::shared_ptr<GroundControlPoint> > m_gcpList;
+};
+
+} // End namespace ISA
+
+#endif
diff --git a/include/ossim/reg/TiePoint.h b/include/ossim/reg/TiePoint.h
new file mode 100644
index 0000000..2fc5ba4
--- /dev/null
+++ b/include/ossim/reg/TiePoint.h
@@ -0,0 +1,126 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#ifndef TiePoint_HEADER
+#define TiePoint_HEADER 1
+
+#include <ossim/base/JsonInterface.h>
+#include <ossim/reg/Image.h>
+#include <ossim/base/ossimDpt.h>
+#include <ossim/imaging/ossimImageHandler.h>
+#include <ossim/matrix/newmat.h>
+#include <vector>
+#include <memory>
+
+namespace ossim
+{
+class TiePoint;
+typedef std::vector< std::shared_ptr<TiePoint> > TiePointList;
+
+/**
+ * Class for representing a single tiepoint on two or more images. It also represents image-points
+ * associated with a ground control point.
+ */
+class TiePoint : public ossim::JsonInterface,
+                 public std::enable_shared_from_this<TiePoint>
+{
+public:
+   enum Type {
+      UNASSIGNED,
+      MANUAL,  //> The point was created or edited manually and contains at least a pair of image points
+      AUTO,    //> Result of auto tie point generation and contains at least a pair of image points
+      GCP      //> point is associated with a manually-entered ground control. Possibly multiple image points
+   };
+
+   TiePoint();
+
+   TiePoint(const TiePoint& copy);
+
+   /**
+   * Creates new tiepoint from JSON object formatted as:
+   * {
+   *    "id": <unsigned int>, // may be ignored if not valid
+   *    "type": "M"|"A"|"G"  For “manual”, “auto”, or “GCP-associated”
+   *    "imagePoints: [
+   *        {
+   *           "imageId": <string>,
+   *           "x": <double>,
+   *           "y": <double>,
+   *           "covariance": [ cxx, cyy, cxy ],
+   *           "gcpId": <string> Only if associated with a GCP
+   *        }
+   *    ]
+   * }
+   */
+   TiePoint(const Json::Value& tp_json_node);
+
+   virtual ~TiePoint();
+
+   unsigned int getImageCount() const { return m_images.size(); }
+
+   const std::string& getTiePointId() const { return m_tiePointId; }
+
+   void setTiePointId(const std::string& id);
+
+   /**
+    * Fetches the image point coordinates along with image ID and GCP ID if available.
+    * @param index Inout index into the list of images containing this tiepoint
+    * @param imageId Output image ID for the ccorresponding image point
+    * @param imagePoint image coordinates
+    * @param cov image point measurement covariance in (x, y) coordinates
+    */
+   void getImagePoint(unsigned int index,
+                      std::string& imageId,
+                      ossimDpt& imagePoint,
+                      NEWMAT::SymmetricMatrix& cov) const;
+
+   /**
+    * Sets image point value and associated measurement covariance for specified image ID.
+    * If the image ID is not found, it will be added as new observation.
+    */
+   void setImagePoint(std::shared_ptr<Image> image,
+                      const ossimDpt& imagePoint,
+                      const NEWMAT::SymmetricMatrix& cov);
+
+   Type getType() const { return m_type; }
+   void setType(Type t) { m_type = t; }
+
+   const std::string& getGcpId() const { return m_gcpId; }
+   void setGcpId(const std::string& id);
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void loadJSON(const Json::Value& json);
+
+   /*
+   * Refer to <a href="https://docs.google.com/document/d/1DXekmYm7wyo-uveM7mEu80Q7hQv40fYbtwZq-g0uKBs/edit?usp=sharing">3DISA API document</a>
+   * for JSON format used.
+   */
+   virtual void saveJSON(Json::Value& json) const;
+
+   virtual std::ostream& print(std::ostream& out) const;
+   friend std::ostream& operator << (std::ostream& out, const TiePoint& tp)
+   { return tp.print(out); }
+
+protected:
+
+   Type m_type;
+   std::string  m_tiePointId;
+   std::vector< std::shared_ptr<Image> > m_images;    //> List of images containing common feature
+   std::vector<ossimDpt> m_imagePoints; //> List of image point measurements for common feature
+   std::vector<NEWMAT::SymmetricMatrix> m_covariances; //> List of measurement covariances corresponding to image points vector
+   double m_gsd; //> image scale (meters/pixel) at which matching was performed
+   std::string m_gcpId; //> Cross reference to GCP record associated with this TP.
+   static int s_runningId;
+};
+
+typedef std::vector< std::shared_ptr<TiePoint> > TiePointList;
+
+} // end namespace ATP
+#endif /* #ifndef TiePoint_HEADER */
diff --git a/include/ossim/util/ossimTool.h b/include/ossim/util/ossimTool.h
index 19c020e..9626fc4 100644
--- a/include/ossim/util/ossimTool.h
+++ b/include/ossim/util/ossimTool.h
@@ -12,13 +12,15 @@
 #include <ossim/base/ossimObject.h>
 #include <ossim/base/ossimArgumentParser.h>
 #include <ossim/base/ossimKeywordlist.h>
+#include <ossim/base/JsonInterface.h>
 #include <iostream>
 
 /*!
  *  Base class for all OSSIM tool applications. These are utilities providing high-level
  *  functionality via the OSSIM library.
  */
-class OSSIM_DLL ossimTool : public ossimObject
+class OSSIM_DLL ossimTool : public ossimObject, public ossim::JsonInterface
+
 {
 public:
    ossimTool();
@@ -43,12 +45,18 @@ public:
    virtual void initialize(const ossimKeywordlist& kwl);
 
    /**
-    * Reads processing params from string provided (usually JSON-formatted, though that's up to the
-    * derived class to implement and contract with consumer). If all good, the object is ready for
+    * Reads processing params from JSON object provided. If all good, the object is ready for
     * subsequent call to execute().
     * @note Throws ossimException on error.
     */
-   virtual void initialize(const std::string& request);
+   virtual void loadJSON(const Json::Value& json_request) {};
+
+   /**
+    * Fetch product as JSON object when applicable
+    * Always returns true since using exception on error.
+    * @param json Returns non-empty object if valid response available.
+    */
+   virtual void saveJSON(Json::Value& json) const { json.clear(); }
 
    /**
     * Writes product to output file if applicable. The product may also beAlways returns true since using exception on error.
diff --git a/scripts/archive.sh b/scripts/archive.sh
index cf2b38c..e6e5d3e 100755
--- a/scripts/archive.sh
+++ b/scripts/archive.sh
@@ -7,7 +7,7 @@
 # This script will create a tarball, e.g. ossim-1.9.0.tar.gz 
 # from a the top level set of ossim git modules, i.e. ossim_labs_dev_root.
 #---
-pushd `dirname $0` >/dev/null
+pushd `dirname ${BASH_SOURCE[0]}` >/dev/null
 export SCRIPT_DIR=$PWD
 popd >/dev/null
 pushd $SCRIPT_DIR/../.. > /dev/null
diff --git a/scripts/build.sh b/scripts/build.sh
index 1284d7d..b6108cd 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -23,13 +23,8 @@
 # Uncomment following line to debug script line by line:
 #set -x; trap read debug
 
-# Working directory must be top-level dir:
-#SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-#pushd $SCRIPT_DIR/../..
-#OSSIM_DEV_HOME=$PWD
-
 #CMAKE_CONFIG_SCRIPT=$OSSIM_DEV_HOME/ossim/cmake/scripts/ossim-cmake-config.sh
-pushd `dirname $0` >/dev/null
+pushd `dirname ${BASH_SOURCE[0]}` >/dev/null
 export SCRIPT_DIR=`pwd -P`
 popd >/dev/null
 # source variables used during the builds
diff --git a/scripts/env.sh b/scripts/env.sh
index 1d2da86..bb0b628 100755
--- a/scripts/env.sh
+++ b/scripts/env.sh
@@ -1,5 +1,5 @@
 #!/bin/bash 
-pushd `dirname $0` >/dev/null
+pushd `dirname ${BASH_SOURCE[0]}` >/dev/null
 export SCRIPT_DIR=`pwd -P`
 popd >/dev/null
 
diff --git a/scripts/install.sh b/scripts/install.sh
index cdea747..048bc9e 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -1,5 +1,5 @@
 #!/bin/bash 
-pushd `dirname $0` >/dev/null
+pushd `dirname ${BASH_SOURCE[0]}` >/dev/null
 export SCRIPT_DIR=`pwd -P`
 popd >/dev/null
 # source variables used during the builds
diff --git a/share/ossim/templates/ossim_preferences_template b/share/ossim/templates/ossim_preferences_template
index 68ab95e..ee95c24 100644
--- a/share/ossim/templates/ossim_preferences_template
+++ b/share/ossim/templates/ossim_preferences_template
@@ -355,7 +355,10 @@ plugin5.file:  $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_kakadu_plugi
 plugin15.file: $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_mrsid_plugin.so
 // plugin15 .options:
 
-plugin16.file: $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_isa_plugin.so
+plugin16.file: $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_msp_plugin.so
+// plugin15 .options:
+
+plugin17.file: $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_atp_plugin.so
 // plugin15 .options:
 
 plugin20.file: $(OSSIM_INSTALL_PREFIX)/lib64/ossim/plugins/libossim_cnes_plugin.so
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5d92e33..b21972e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@ FILE(GLOB ossim_SRCS  RELATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}
         "${CMAKE_CURRENT_SOURCE_DIR}/ossimConfig*.cpp" 
         "${CMAKE_CURRENT_SOURCE_DIR}/ossimVer*.cpp" 
         "${CMAKE_CURRENT_SOURCE_DIR}/init/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/init/*.c" 
+        "${CMAKE_CURRENT_SOURCE_DIR}/reg/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/reg/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/base/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/base/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/elevation/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/elevation/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/font/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/font/*.c" 
@@ -13,6 +14,7 @@ FILE(GLOB ossim_SRCS  RELATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}
         "${CMAKE_CURRENT_SOURCE_DIR}/point_cloud/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/point_cloud/*.c"
         "${CMAKE_CURRENT_SOURCE_DIR}/projection/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/projection/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/support_data/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/support_data/*.c" 
+        "${CMAKE_CURRENT_SOURCE_DIR}/reg/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/reg/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/util/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/util/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/vec/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/vec/*.c" 
         "${CMAKE_CURRENT_SOURCE_DIR}/video/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/video/*.c" 
@@ -49,6 +51,7 @@ FILE(GLOB ossim_elevation_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_C
 FILE(GLOB ossim_font_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/font/*.h")
 FILE(GLOB ossim_imaging_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/imaging/*.h")
 FILE(GLOB ossim_init_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/init/*.h")
+FILE(GLOB ossim_reg_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/reg/*.h")
 FILE(GLOB ossim_matrix_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/matrix/*.h")
 FILE(GLOB ossim_parallel_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/parallel/*.h")
 FILE(GLOB ossim_plugin_HDRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../include/ossim/plugin/*.h")
@@ -72,7 +75,7 @@ MESSAGE( "${ossim_HDRS}" )
 SET(OSSIM_HEADER_FILES 
   ${ossim_HDRS}
   ${ossim_base_HDRS} ${ossim_elevation_HDRS} ${ossim_font_HDRS}  ${ossim_imaging_HDRS} 
-  ${ossim_init_HDRS} ${ossim_matrix_HDRS} ${ossim_parallel_HDRS} ${ossim_plugin_HDRS} 
+  ${ossim_init_HDRS} ${ossim_reg_HDRS} ${ossim_matrix_HDRS} ${ossim_parallel_HDRS} ${ossim_plugin_HDRS} 
   ${ossim_point_cloud_HDRS} ${ossim_projection_HDRS} ${ossim_support_data_HDRS} ${ossim_util_HDRS} 
   ${ossim_vec_HDRS} ${ossim_video_HDRS} ${ossim_vpfutil_HDRS} ${ossim_sockets_HDRS} ${ossim_hdf5_HDRS} )
 
@@ -97,6 +100,9 @@ IF(APPLE)
   FOREACH(f  ${ossim_init_HDRS} )
       SET_SOURCE_FILES_PROPERTIES( ${f} PROPERTIES MACOSX_PACKAGE_LOCATION Headers/init )
   ENDFOREACH(f)
+  FOREACH(f  ${ossim_reg_HDRS} )
+      SET_SOURCE_FILES_PROPERTIES( ${f} PROPERTIES MACOSX_PACKAGE_LOCATION Headers/reg )
+  ENDFOREACH(f)
   FOREACH(f  ${ossim_matrix_HDRS} )
       SET_SOURCE_FILES_PROPERTIES( ${f} PROPERTIES MACOSX_PACKAGE_LOCATION Headers/matrix )
   ENDFOREACH(f)
@@ -158,6 +164,7 @@ IF(NOT OSSIM_BUILD_FRAMEWORKS OR NOT APPLE)
    install(FILES ${ossim_font_HDRS} DESTINATION include/ossim/font COMPONENT ossim)
    install(FILES ${ossim_imaging_HDRS} DESTINATION include/ossim/imaging COMPONENT ossim) 
    install(FILES ${ossim_init_HDRS} DESTINATION include/ossim/init COMPONENT ossim) 
+   install(FILES ${ossim_reg_HDRS} DESTINATION include/ossim/reg COMPONENT ossim) 
    install(FILES ${ossim_matrix_HDRS} DESTINATION include/ossim/matrix COMPONENT ossim) 
    install(FILES ${ossim_parallel_HDRS} DESTINATION include/ossim/parallel COMPONENT ossim) 
    install(FILES ${ossim_plugin_HDRS} DESTINATION include/ossim/plugin COMPONENT ossim) 
diff --git a/src/base/ossimKeywordlist.cpp b/src/base/ossimKeywordlist.cpp
index 4a343dc..2e7b806 100755
--- a/src/base/ossimKeywordlist.cpp
+++ b/src/base/ossimKeywordlist.cpp
@@ -13,17 +13,19 @@
 #include <ossim/base/ossimIoStream.h>
 
 #include <ossim/base/ossimNotify.h>
+#include <ossim/base/ossimRefPtr.h>
 #include <ossim/base/ossimRegExp.h>
+#include <ossim/base/ossimStreamFactoryRegistry.h>
 #include <ossim/base/ossimTrace.h>
+#include <ossim/base/ossimXmlNode.h>
 
 #include <algorithm>
 #include <fstream>
 #include <list>
+#include <memory>
 #include <sstream>
 #include <utility>
-#include <cstddef> // nullptr
 
-#include <ossim/base/BlockIStream.h>
 #include <ossim/base/ossimStreamFactoryRegistry.h>
 
 static ossimTrace traceDebug("ossimKeywordlist:debug");
@@ -728,16 +730,15 @@ bool ossimKeywordlist::parseFile(const ossimFilename& file,
 {
    bool result = false;
 
-   std::shared_ptr<ossim::ifstream> is = std::make_shared<ossim::ifstream>(file.c_str(), 
-                                                std::ios::in | std::ios::binary);
-   if(is&&is->is_open())
+   std::shared_ptr<ossim::istream> is = ossim::StreamFactoryRegistry::instance()->
+      createIstream( file.string() );
+   if ( is )
    {
-      std::shared_ptr<ossim::BlockIStream> blockedStream = std::make_shared<ossim::BlockIStream>(is, 4096);
       m_currentlyParsing = file;
       result = parseStream(*is, ignoreBinaryChars);
+      is.reset();
    }
-
-   is = nullptr;
+   
    return result;
 }
 
@@ -1094,7 +1095,7 @@ void ossimKeywordlist::getSortedList(std::vector<ossimString>& prefixValues,
    ossim_uint32 offset = (int)ossimString(prefixKey).size();
    ossim_uint32 idx = 0;
    std::vector<ossim_uint32> numberList(nKeys);
-   for(idx = 0; idx < (int)numberList.size();++idx)
+   for(idx = 0; idx < (ossim_uint32)numberList.size();++idx)
    {
     ossimString numberStr(keys[idx].begin() + offset,
            keys[idx].end());
@@ -1102,7 +1103,7 @@ void ossimKeywordlist::getSortedList(std::vector<ossimString>& prefixValues,
    }
    std::sort(numberList.begin(), numberList.end());
 
-   for(idx=0;idx < (int)numberList.size();++idx)
+   for(idx=0;idx < (ossim_uint32)numberList.size();++idx)
    {
       prefixValues.push_back(prefixKey+ossimString::toString(numberList[idx]));
    }
@@ -1473,3 +1474,407 @@ bool ossimKeywordlist::getBoolKeywordValue(bool& rtn_val,
    return found;
 }
 
+bool ossimKeywordlist::isSpecialXmlCharacters(const ossimString& value)const
+{
+   for(ossimString::const_iterator it = value.begin(); it != value.end();++it)
+   {
+      switch(*it)
+      {
+         case '&':
+         case '<':
+         case '>':
+         case '"':
+         case '\'':
+         {
+            return true;
+         }
+         default:
+         {
+            break;
+         }
+      }
+      
+   }
+   return false;
+}
+
+bool ossimKeywordlist::isValidTag(const std::string& value)const
+{
+   std::string::const_iterator textChars = value.begin();
+   bool result = true;
+   if(!isalpha(*(textChars) ))
+   {
+      result = false;
+   }
+   else if(!value.empty())
+   {
+      for(++textChars;textChars!=value.end();++textChars)
+      {
+         if(!isalnum(*(textChars) ))
+         {
+            result = false;
+            break;
+         }
+      }
+   }
+   else
+   {
+      result = false;
+   }
+   
+   return result;
+}
+
+void ossimKeywordlist::replaceSpecialCharacters(ossimString& value)const
+{
+   ossimString::iterator iter = value.begin();
+   
+   while(iter!=value.end())
+   {
+      if(!(isdigit(*iter) ||
+           isalpha(*iter)||
+           (*iter=='/')))
+      {
+         *iter = '_';
+      }
+      ++iter;
+   }
+}
+
+void ossimKeywordlist::toXML(std::ostream& out, const std::string& rootTag)const
+{
+   std::string rootTagStr = rootTag;
+   if (!isValidTag(rootTagStr))
+   {
+      rootTagStr = "info";
+   }
+
+   ossimRefPtr<ossimXmlNode> metadata = new ossimXmlNode;
+   metadata->setTag("metadata");
+   ossimKeywordlist::KeywordMap::const_iterator iter = m_map.begin();
+   while(iter != m_map.end())
+   {
+      ossimString path = iter->first;
+      bool outputValue = true;
+      ossimString value = iter->second;
+      if(path.contains("unformatted_tag_data"))
+      {
+         ossimString temp = value.trim();
+         if(ossimString(temp.begin(), temp.begin()+5) == "<?xml")
+         {
+            value = "XML not converted";
+            outputValue = false;
+         }
+      }
+      
+      if(outputValue)
+      {
+         bool tagOk = true;
+         path = path.substitute(".", "/", true);
+         replaceSpecialCharacters(path);
+         std::vector<ossimString> splitValues;
+         path.split(splitValues,"/");
+         if(splitValues.size())
+         {
+            splitValues[splitValues.size()-1] = splitValues[splitValues.size()-1].downcase();
+            ossim_uint32 idx = 0;
+            for(idx = 0; ((idx < splitValues.size()-1)&&tagOk);++idx)
+            {
+               if(!isValidTag(splitValues[idx]))
+               {
+                  tagOk = false;
+               }
+               splitValues[idx] = splitValues[idx].upcase();
+            }
+         }
+         if(tagOk)
+         {
+            path.join(splitValues, "/");
+            ossimRefPtr<ossimXmlNode> node = metadata->addNode(path.c_str(), value);
+            if(isSpecialXmlCharacters(value))
+            {
+               node->setCDataFlag(true);
+            }
+         }
+      }
+      ++iter;
+   }
+   
+   if( 1 ) // tmp dbr !m_includeMetadataTagName)
+   {
+      out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl
+          << "<" << rootTagStr << ">\n";
+      
+      const ossimXmlNode::ChildListType& children = metadata->getChildNodes();
+      ossimXmlNode::ChildListType::const_iterator iter = children.begin();
+      while(iter != children.end())
+      {
+         out << *(iter->get());
+         ++iter;
+      }
+      out << "\n</" << rootTagStr << ">" << std::endl;
+   }
+   else 
+   {
+      out << *(metadata.get()) << std::endl;
+   }   
+}
+
+
+void ossimKeywordlist::toJSON(std::ostream& out, const std::string& rootTag)const
+{
+   const std::string C   = ": "; // colon
+   const std::string DQ  = "\""; // double Quote
+   const std::string LB  = "{"; // left bracket
+   const std::string CNL = ",\n"; // coma, new line
+   const std::string NL  = "\n"; // new line   
+   const std::string RB  = "}"; // left bracket
+   const std::string S   = " ";  // space
+   ossim_uint32 nameCount = 0;
+   ossimString lastObject;
+   ossim_uint32 indentCount = 3;
+   ossim_uint32 indentOffset = 3;
+   
+   bool stringify = true;
+   bool closeObject = false;
+   std::vector<ossimString> objectStack;
+
+   // Opening bracket:
+   out << LB;
+   
+   if( rootTag.size() )
+   {
+      if ( stringify )
+      {
+         indentOffset = indentCount;
+         std::string indent(indentCount, ' ');
+         out << NL << indent;
+      }
+      else
+      {
+         out << NL;
+      }
+      // Note: not adding rootTag to object stack
+      out << DQ << rootTag << DQ << C << LB << NL;
+   }
+
+   ossimKeywordlist::KeywordMap::const_iterator iter = m_map.begin();
+   while(iter != m_map.end())
+   {
+      bool outputValue  = true;
+      ossimString key   = iter->first;
+      ossimString value = iter->second;
+      value = value.trim(); // remove spaces
+
+#if 0
+      if(key.contains("unformatted_tag_data"))
+      {
+         ossimString temp = value.trim();
+         if(ossimString(temp.begin(), temp.begin()+5) == "<?xml")
+         {
+            value = "data not converted";
+            outputValue = false;
+         }
+      }
+#endif
+      
+      if ( outputValue && key.size() )
+      {
+         std::vector<ossimString> keys;
+         key.split(keys,".");
+         
+         if ( keys.size() )
+         {
+            // The last key is the name so grab it now and pop it off the stack:
+            ossimString name = keys[keys.size()-1];
+            keys.pop_back();
+
+            bool sameObject = isSame( keys, objectStack );
+            if ( !sameObject && keys.size() )
+            {
+               for ( ossim_uint32 i = 0; i < keys.size(); ++i )
+               {
+                  if ( i < objectStack.size() )
+                  {
+                     if ( keys[i] == objectStack[i] )
+                     {
+                        // On stack already. Nothng to do. Go to next key.
+                        continue;
+                     }
+                     else
+                     {
+                        // Different object:
+                        while ( i <  objectStack.size() )
+                        {
+                           // Write bracket, then pop:
+                           if ( stringify )
+                           {
+                              std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
+                              out << NL << indent << RB;
+                           }
+                           else
+                           {
+                              out << NL << RB;
+                           }
+                           objectStack.pop_back();
+                           nameCount = 0;
+                           closeObject = true;
+                           if ( objectStack.size() )
+                           {
+                              lastObject = objectStack[objectStack.size()-1];
+                           }
+                           else
+                           {
+                              lastObject.clear();
+                           }
+                        }
+                     }
+                  }
+                  
+                  //---
+                  // New object:
+                  // If we had written a key:value for previos object, do a
+                  // newline and zero it out.
+                  //---
+                  if ( nameCount )
+                  {
+                     out << CNL;
+                     nameCount = 0;
+                  }
+                        
+                  objectStack.push_back( keys[i] );
+
+                  if ( closeObject )
+                  {
+                     out << CNL;
+                     closeObject = false;
+                  }
+
+                  if ( stringify )
+                  {
+                     std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
+                     out << indent;
+                  }
+                  out << DQ << keys[i] << DQ << C << LB << NL;
+               }
+
+               // Final check if keys shrunk, pop objects off the object stack.
+               while ( keys.size() <  objectStack.size() )
+               {
+                  // Write bracket then pop:
+                  if ( stringify )
+                  {
+                     std::string indent(indentOffset+(indentCount*objectStack.size()), ' ');
+                     out << NL << indent << RB;
+                  }
+                  else
+                  {
+                     out << NL << RB;
+                  }
+                  objectStack.pop_back();
+                  nameCount = 0;
+                  closeObject = true;
+                  if ( objectStack.size() )
+                  {
+                     lastObject = objectStack[objectStack.size()-1];
+                  }
+                  else
+                  {
+                     lastObject.clear();
+                  }
+               }
+            }
+
+            if ( objectStack.size() )
+            {       
+               if ( lastObject == objectStack[objectStack.size()-1] )
+               {
+                  out << CNL;
+                  closeObject = false;
+               }
+            }
+            else if ( nameCount ) // No objects loaded on the stack.
+            {
+               out << CNL;
+            }  
+
+            // Output "key": "value"
+            if ( stringify )
+            {
+               std::string indent(indentOffset+indentCount*(objectStack.size()+1), ' ');
+               out << indent;
+            }
+            out << DQ << name << DQ << C << DQ << value << DQ;
+
+            if ( objectStack.size() )
+            {
+               lastObject = objectStack[objectStack.size()-1];
+            }
+            else
+            {
+               lastObject.clear();
+            }
+            
+            ++nameCount;
+         }
+      }
+      ++iter;
+      
+   } // Matches: while(iter != m_map.end())
+
+   // Close out brackets:
+   ossim_uint32 stackSize = objectStack.size();
+   if ( stackSize )
+   {
+      for ( ossim_uint32 i = stackSize; i > 0; --i )
+      {
+         if ( stringify )
+         {
+            std::string indent(indentOffset+indentCount*i, ' ');
+            out << NL << indent << RB;
+         }
+         else
+         {
+            out << NL << RB;
+         }
+      }
+   }
+
+   if( rootTag.size() )
+   {
+      if ( stringify )
+      {
+         std::string indent(indentCount, ' ');
+         out << NL << indent << RB;
+      }
+      else
+      {
+         out << NL << RB;
+      }
+   }
+   
+   // Closing bracket, newline with flush:
+   out << NL << RB << std::endl;
+}
+
+bool ossimKeywordlist::isSame( const std::vector<ossimString>& a,
+                               const std::vector<ossimString>& b ) const
+{
+   bool result = true;
+   if ( a.size() == b.size() )
+   {
+      for ( ossim_uint32 i = 0; i < a.size(); ++i )
+      {
+         if ( a[i] != b[i] )
+         {
+            result = false;
+            break;
+         }
+      }
+   }
+   else
+   {
+      result = false;
+   }
+   return result;
+}
diff --git a/src/imaging/ossimImageRenderer.cpp b/src/imaging/ossimImageRenderer.cpp
index 92e1fc4..187cdd6 100644
--- a/src/imaging/ossimImageRenderer.cpp
+++ b/src/imaging/ossimImageRenderer.cpp
@@ -1873,19 +1873,26 @@ void ossimImageRenderer::getValidImageVertices(vector<ossimIpt>& validVertices,
 //*************************************************************************************************
 ossimRefPtr<ossimImageGeometry> ossimImageRenderer::getImageGeometry()
 {
-   // Make sure the IVT was properly initialized
-   if (m_ImageViewTransform.valid() && !m_ImageViewTransform->isValid())
-      checkIVT();
+   ossimRefPtr<ossimImageGeometry> geom = 0;
+   if (isSourceEnabled())
+   {
+      // Make sure the IVT was properly initialized
+      if (m_ImageViewTransform.valid() && !m_ImageViewTransform->isValid())
+         checkIVT();
 
-   ossimImageViewProjectionTransform* ivpt = 
-                   dynamic_cast<ossimImageViewProjectionTransform*>(m_ImageViewTransform.get()); 
-   if (ivpt)
+      ossimImageViewProjectionTransform* ivpt =
+            dynamic_cast<ossimImageViewProjectionTransform*>(m_ImageViewTransform.get());
+      if (ivpt)
+      {
+         // we need to return the right side since the geometry changed to a view geometry
+         geom = ivpt->getViewGeometry();
+      }
+   }
+   else if (theInputConnection)
    {
-      // we need to return the right side since the geometry changed to a view geometry
-      return ivpt->getViewGeometry();
+      geom = theInputConnection->getImageGeometry();
    }
-
-   return ossimRefPtr<ossimImageGeometry>();
+   return geom;
 }
 
 void ossimImageRenderer::connectInputEvent(ossimConnectionEvent& /* event */)
diff --git a/src/imaging/ossimImageWriterFactory.cpp b/src/imaging/ossimImageWriterFactory.cpp
index 2a00960..d555e56 100644
--- a/src/imaging/ossimImageWriterFactory.cpp
+++ b/src/imaging/ossimImageWriterFactory.cpp
@@ -8,7 +8,7 @@
 // Author:  Garrett Potts
 //
 //*******************************************************************
-// $Id: ossimImageWriterFactory.cpp 22242 2013-04-20 02:16:06Z gpotts $
+// $Id$
 
 #include <ossim/imaging/ossimImageWriterFactory.h>
 #include <ossim/base/ossimImageTypeLut.h>
@@ -148,7 +148,6 @@ ossimImageWriterFactory::createWriter(const ossimString& typeName)const
    }
 
    writer = new ossimTiffWriter;
-   
    if (STATIC_TYPE_NAME(ossimTiffWriter) == typeName )
    {
       return writer.release();
@@ -321,7 +320,7 @@ void ossimImageWriterFactory::getTypeNameList(std::vector<ossimString>& typeList
    typeList.push_back(STATIC_TYPE_NAME(ossimNitfWriter));
    typeList.push_back(STATIC_TYPE_NAME(ossimNitf20Writer));
    typeList.push_back(STATIC_TYPE_NAME(ossimPdfWriter));
-   typeList.push_back(STATIC_TYPE_NAME(ossimWriter));
+   typeList.push_back(ossimString("ossimWriter"));
 }
 
 void ossimImageWriterFactory::getImageFileWritersBySuffix(
diff --git a/src/imaging/ossimWriter.cpp b/src/imaging/ossimWriter.cpp
index d7a1d82..0539ac9 100644
--- a/src/imaging/ossimWriter.cpp
+++ b/src/imaging/ossimWriter.cpp
@@ -10,7 +10,11 @@
 // $Id$
 
 #include <ossim/imaging/ossimWriter.h>
+#include <ossim/base/ossimBooleanProperty.h>
 #include <ossim/base/ossimCommon.h>
+#include <ossim/base/ossimKeywordNames.h>
+#include <ossim/base/ossimProperty.h>
+#include <ossim/base/ossimStringProperty.h>
 #include <ossim/base/ossimRefPtr.h>
 #include <ossim/base/ossimTiffConstants.h>
 #include <ossim/base/ossimTrace.h>
@@ -21,20 +25,38 @@
 #include <limits>
 #include <ostream>
 
-static const ossimTrace traceDebug("ossimWriter:debug");
+static const std::string ALIGN_TILES_KW         = "align_tiles";         // bool
+static const std::string BLOCK_SIZE_KW          = "block_size";          // unsigned int
+static const std::string FLUSH_TILES_KW         = "flush_tiles";         // bool
+static const std::string INCLUDE_BLANK_TILES_KW = "include_blank_tiles"; // bool
+static const std::string TILE_SIZE_KW           = "tile_size";           // (x,y) in pixels
+static const std::string TRUE_KW                = "true";
 
-using namespace std; // tmp drb
+static const ossimTrace traceDebug("ossimWriter:debug");
 
 ossimWriter::ossimWriter()
    : ossimImageFileWriter(),
      m_str(0),
-     m_ownsStreamFlag(false)
+     m_ownsStreamFlag(false),
+     m_kwl(new ossimKeywordlist()),
+     m_outputTileSize(OSSIM_DEFAULT_TILE_WIDTH, OSSIM_DEFAULT_TILE_HEIGHT)
 {
+   // Set default options:
+   ossim::defaultTileSize(m_outputTileSize);
+   
+   m_kwl->addPair( ALIGN_TILES_KW, TRUE_KW );
+   m_kwl->addPair( BLOCK_SIZE_KW, "4096" );
+   m_kwl->addPair( FLUSH_TILES_KW, TRUE_KW );
+   m_kwl->addPair( INCLUDE_BLANK_TILES_KW, TRUE_KW );
+   m_kwl->addPair( TILE_SIZE_KW, m_outputTileSize.toString().string() );
 }
 
 ossimWriter::~ossimWriter()
 {
    close();
+
+   // Not a leak, ref ptr.
+   m_kwl = 0;
 }
 
 void ossimWriter::close()
@@ -70,7 +92,7 @@ ossimString ossimWriter::getClassName() const
 ossimString ossimWriter::getExtension() const
 {
    ossimString result = "";
-   if ( theOutputImageType == "ttbs" ) // tiled tiff band separate
+   if ( theOutputImageType == "ossim_ttbs" ) // tiled tiff band separate
    {
       result = "tif";
    }
@@ -146,6 +168,9 @@ bool ossimWriter::writeFile()
       if ( status )
       {
          status = writeStream();
+
+         // Flush and close the stream.
+         close();
       }
    }
 
@@ -167,6 +192,14 @@ bool ossimWriter::writeStream()
       {
          if ( theOutputImageType == "ossim_ttbs" )
          {
+            if ( (theInputConnection->getTileWidth()  !=
+                  static_cast<ossim_uint32>(m_outputTileSize.x)) ||
+                 (theInputConnection->getTileHeight() !=
+                  static_cast<ossim_uint32>(m_outputTileSize.y)) )
+            {
+               theInputConnection->setTileSize(m_outputTileSize);
+            }
+            
             status = writeStreamTtbs();
          }
       }
@@ -232,10 +265,7 @@ bool ossimWriter::writeTiffHdr()
    us16 = 0;
    m_str->write( (const char*)&us16, 2 );
 
-   //---
-   // Offset to first IFD(image file directory).
-   // This will be updated by writeTiffTags method.
-   //---
+   // Offset to the IFD(image file directory).
    ossim_uint64 ul64 = 16;
    m_str->write( (const char*)&ul64, 8 );
    
@@ -257,24 +287,19 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       mapProj = dynamic_cast<ossimMapProjection*>( proj.get() );
    }
    
-   // Seek back and set the image file dectory offset(ifd).
-   std::streamoff currentPos = m_str->tellp();
-
-   m_str->seekp( 8, std::ios_base::beg );
+   // Seek to the IFD.
+   m_str->seekp( 16, std::ios_base::beg );
    
-   ossim_uint64 ifdOffset = (ossim_uint64)currentPos;
-   m_str->write( (const char*)&ifdOffset, 8 );
+   // tag count, this will be rewritten at the end:
+   ossim_uint64 tagCount = 0;
+   m_str->write( (const char*)&tagCount, 8 );
 
-   // Seek back to ifd:
-   m_str->seekp( currentPos, std::ios_base::beg );
-   
-   // tag count:
-   ossim_uint64 ul64 = mapProj.valid() ? 18 : 14; // tmp drb
-   m_str->write( (const char*)&ul64, 8 );
-
-   // Set the sart position for array writing.
-   std::streamoff arrayWritePos = m_str->tellp();
-   arrayWritePos += 24 * 20; // tmp drb
+   //---
+   // This is where the tile offsets, tile byte counts and arrays bytes are
+   // written. Starting at byte position 512 which gives from
+   // 16 -> 512(496 bytes) to write tags.
+   //---
+   std::streamoff arrayWritePos = 512;
 
    // Used throughout:
    ossim_uint16 tag;
@@ -298,6 +323,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       value_ui32 = theAreaOfInterest.width();
       writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
    }
+   ++tagCount;
    
    // image length tag 257:
    tag   = ossim::OTIFFTAG_IMAGELENGTH;
@@ -311,9 +337,10 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
    else
    {
       type = ossim::OTIFF_LONG;
-      value_ui32 = theAreaOfInterest.width();
+      value_ui32 = theAreaOfInterest.height();
       writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
-   }   
+   }
+   ++tagCount;
 
    // bits per sample tag 258:
    tag   = ossim::OTIFFTAG_BITSPERSAMPLE;
@@ -329,6 +356,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       std::vector<ossim_uint16> v(count, value_ui16);
       writeTiffTag<ossim_uint16>( tag, type, count, &v.front(), arrayWritePos );
    }
+   ++tagCount;
 
    // compression tag 259:
    tag   = ossim::OTIFFTAG_COMPRESSION;
@@ -336,6 +364,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
    count = 1;
    value_ui16 = ossim::COMPRESSION_NONE; // tmp only uncompressed supported.
    writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
+   ++tagCount;
    
    // photo interpretation tag 262:
    tag   = ossim::OTIFFTAG_PHOTOMETRIC;
@@ -349,8 +378,8 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
    {
       value_ui16 = ossim::OPHOTO_MINISBLACK;
    }
-   
    writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
+   ++tagCount;
 
    // samples per pixel tag 277:
    tag   = ossim::OTIFFTAG_SAMPLESPERPIXEL;
@@ -358,47 +387,57 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
    count = 1;
    value_ui16 = theInputConnection->getNumberOfOutputBands();
    writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
+   ++tagCount;
 
    // Writes two tags 280 and 281:
-   writeMinMaxTiffTags( minBands, maxBands, arrayWritePos );
-
+   if ( writeMinMaxTiffTags( arrayWritePos ) == true )
+   {
+      tagCount += 2;  
+   }
+   
    // planar conf tag 284:
    tag   = ossim::OTIFFTAG_PLANARCONFIG;
    type  = ossim::OTIFF_SHORT;
    count = 1;
    value_ui16 = ossim::OTIFFTAG_PLANARCONFIG_SEPARATE;
    writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
-   
-   // tile width tag 322:
-   tag   = ossim::OTIFFTAG_TILEWIDTH;
-   count = 1;
-   if ( theInputConnection->getTileWidth() <= OSSIM_DEFAULT_MAX_PIX_UINT16 )
-   {
-      type = ossim::OTIFF_SHORT;
-      value_ui16 = (ossim_uint16)theInputConnection->getTileWidth();
-      writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
-   }
-   else
-   {
-      type = ossim::OTIFF_LONG;
-      value_ui32 = theAreaOfInterest.width();
-      writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
-   }
+   ++tagCount;
 
-   // tile length tag 323:
-   tag   = ossim::OTIFFTAG_TILELENGTH;
-   count = 1;
-   if ( theInputConnection->getTileHeight() <= OSSIM_DEFAULT_MAX_PIX_UINT16 )
+   if ( isTiled() )
    {
-      type = ossim::OTIFF_SHORT;
-      value_ui16 = (ossim_uint16)theInputConnection->getTileWidth();
-      writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
-   }
-   else
-   {
-      type = ossim::OTIFF_LONG;
-      value_ui32 = theAreaOfInterest.width();
-      writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
+      // tile width tag 322:
+      tag   = ossim::OTIFFTAG_TILEWIDTH;
+      count = 1;
+      if (  m_outputTileSize.x <= OSSIM_DEFAULT_MAX_PIX_UINT16 )
+      {
+         type = ossim::OTIFF_SHORT;
+         value_ui16 = (ossim_uint16)m_outputTileSize.x;
+         writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
+      }
+      else
+      {
+         type = ossim::OTIFF_LONG;
+         value_ui32 = (ossim_uint32)m_outputTileSize.x;
+         writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
+      }
+      ++tagCount;
+      
+      // tile length tag 323:
+      tag   = ossim::OTIFFTAG_TILELENGTH;
+      count = 1;
+      if (  m_outputTileSize.y <= OSSIM_DEFAULT_MAX_PIX_UINT16 )
+      {
+         type = ossim::OTIFF_SHORT;
+         value_ui16 = (ossim_uint16)m_outputTileSize.y;
+         writeTiffTag<ossim_uint16>( tag, type, count, &value_ui16, arrayWritePos );
+      }
+      else
+      {
+         type = ossim::OTIFF_LONG;
+         value_ui32 = (ossim_uint32)m_outputTileSize.y;
+         writeTiffTag<ossim_uint32>( tag, type, count, &value_ui32, arrayWritePos );
+      }
+      ++tagCount;
    }
 
    // tile offsets tag 324:
@@ -406,12 +445,14 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
    count = tile_offsets.size();
    type  = ossim::OTIFF_LONG8;
    writeTiffTag<ossim_uint64>( tag, type, count, &tile_offsets.front(), arrayWritePos );
+   ++tagCount;
 
    // tile byte counts tag 325:
    tag   = ossim::OTIFFTAG_TILEBYTECOUNTS;
    count = tile_byte_counts.size();
    type  = ossim::OTIFF_LONG8;
    writeTiffTag<ossim_uint64>( tag, type, count, &tile_byte_counts.front(), arrayWritePos );
+   ++tagCount;
 
    // sample format tag 339:
    tag   = ossim::OTIFFTAG_SAMPLEFORMAT;
@@ -427,9 +468,13 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       std::vector<ossim_uint16> v(count, value_ui16);
       writeTiffTag<ossim_uint16>( tag, type, count, &v.front(), arrayWritePos );
    }
+   ++tagCount;
 
    // Writes two tags 340 and 341 (conditional on scalar type):
-   writeSMinSMaxTiffTags( minBands, maxBands, arrayWritePos );
+   if ( writeSMinSMaxTiffTags( minBands, maxBands, arrayWritePos ) == true )
+   {
+      tagCount += 2;
+   }
 
    // Write geo keys if valid map projection:
    if ( mapProj.valid() )
@@ -461,6 +506,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       vf[1] = scale.y;
       vf[2] = 0.0;
       writeTiffTag<ossim_float64>( tag, type, count, &vf.front(), arrayWritePos );
+      ++tagCount;
 
       // model tie point tag 33992:
       tag   = ossim::OMODEL_TIE_POINT_TAG;
@@ -474,6 +520,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       vf[4] = tie.y; // latitude of northing
       vf[5] = 0.0;
       writeTiffTag<ossim_float64>( tag, type, count, &vf.front(), arrayWritePos );
+      ++tagCount;
 
       // geo key directory tag 34735:
       tag   = ossim::OGEO_KEY_DIRECTORY_TAG;
@@ -556,6 +603,7 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       count = vs.size();
       vs[3] = (count / 4) - 1;
       writeTiffTag<ossim_uint16>( tag, type, count, &vs.front(), arrayWritePos );
+      ++tagCount;
        
       // geo double params tag 33550:
       tag   = ossim::OGEO_DOUBLE_PARAMS_TAG;
@@ -565,110 +613,80 @@ bool ossimWriter::writeTiffTags( const std::vector<ossim_uint64>& tile_offsets,
       vf[0] = mapProj->getDatum()->ellipsoid()->a();
       vf[1] = mapProj->getDatum()->ellipsoid()->b();
       writeTiffTag<ossim_float64>( tag, type, count, &vf.front(), arrayWritePos );
+      ++tagCount;
    }
 
-   // Last write is zero indicading no more ifds.
+   // Write trailing zero indicading no more IFDs.
    ossim_uint64 offsetToNextIfd = 0;
    m_str->write( (const char*)&offsetToNextIfd, 8 );
 
+   // Seek back and re-write the tag count.
+   m_str->seekp( 16, std::ios_base::beg );
+   m_str->write( (const char*)&tagCount, 8 );
+   
    status =  m_str->good();
    
    return status;
 }
 
-bool ossimWriter::writeMinMaxTiffTags( const vector<ossim_float64>& minBands,
-                                       const vector<ossim_float64>& maxBands,
-                                       std::streamoff& arrayWritePos )
+bool ossimWriter::writeMinMaxTiffTags( std::streamoff& arrayWritePos )
 {
    bool status = true;
-   
-   if(minBands.size() && maxBands.size())
-   {
-      ossim_float64 minValue = *std::min_element(minBands.begin(), minBands.end());
-      ossim_float64 maxValue = *std::max_element(maxBands.begin(), maxBands.end());
 
-      switch( theInputConnection->getOutputScalarType() )
+   // DEFAULT for OSSIM_UINT32.
+   ossim_uint16 minValue = 1;
+   ossim_uint16 maxValue = 255;
+
+   switch( theInputConnection->getOutputScalarType() )
+   {
+      case OSSIM_UINT8:
       {
-         case OSSIM_USHORT11:
-         {
-            ossim_uint16 v = 0;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = 2047;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                       ossim::OTIFF_SHORT,
-                                       1, &v, arrayWritePos );
-            break;
-         }
-         case OSSIM_USHORT12:
-         {
-            ossim_uint16 v = 0;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = 4095;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                       ossim::OTIFF_SHORT,
-                                       1, &v, arrayWritePos );
-            break;
-         }
-         case OSSIM_USHORT13:
-         {
-            ossim_uint16 v = 0;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = 8191;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                       ossim::OTIFF_SHORT,
-                                       1, &v, arrayWritePos );
-            break;
-         }
-         case OSSIM_USHORT14:
-         {
-            ossim_uint16 v = 0;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = 16383;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                       ossim::OTIFF_SHORT,
-                                       1, &v, arrayWritePos );
-            break;
-         }
-         case OSSIM_USHORT15:
-         {
-            ossim_uint16 v = 0;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = 32767;
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                       ossim::OTIFF_SHORT,
-                                       1, &v, arrayWritePos );
-            break;
-         }
-         case OSSIM_UINT8:
-         case OSSIM_UINT16:
-         {
-            ossim_uint16 v = static_cast<ossim_uint16>(minValue);
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            v = static_cast<ossim_uint16>(maxValue);
-            writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
-                                        ossim::OTIFF_SHORT,
-                                        1, &v, arrayWritePos );
-            break;
-         }
-         default:
-         {
-            status = false;
-            break;
-         }
+         break; // defaulted above
       }
+      case OSSIM_USHORT11:
+      {
+         maxValue = 2047;
+         break;
+      }
+      case OSSIM_USHORT12:
+      {
+         maxValue = 4095;
+         break;
+      }
+      case OSSIM_USHORT13:
+      {
+         maxValue = 8191;
+         break;
+      }
+      case OSSIM_USHORT14:
+      {
+         maxValue = 16383;
+         break;
+      }
+      case OSSIM_USHORT15:
+      {
+         maxValue = 32767;
+         break;
+      }
+      case OSSIM_UINT16:
+      {
+         maxValue = 65535;
+         break;
+      }
+      default:
+         status = false;
+   }
+   
+   if ( status )
+   {
+      writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MINSAMPLEVALUE,
+                                  ossim::OTIFF_SHORT,
+                                  1, &minValue, arrayWritePos );
+      writeTiffTag<ossim_uint16>( ossim::OTIFFTAG_MAXSAMPLEVALUE,
+                                  ossim::OTIFF_SHORT,
+                                  1, &maxValue, arrayWritePos );
    }
+   
    return status;
 }
 
@@ -676,7 +694,7 @@ bool ossimWriter::writeSMinSMaxTiffTags( const vector<ossim_float64>& minBands,
                                          const vector<ossim_float64>& maxBands,
                                          std::streamoff& arrayWritePos )
 {
-   bool status = true;
+   bool status = false;
    
    if(minBands.size() && maxBands.size())
    {
@@ -700,11 +718,11 @@ bool ossimWriter::writeSMinSMaxTiffTags( const vector<ossim_float64>& minBands,
             writeTiffTag<ossim_float32>( ossim::OTIFFTAG_SMAXSAMPLEVALUE,
                                          ossim::OTIFF_FLOAT,
                                          1, &v, arrayWritePos );
+            status = true;
             break;
          }
          default:
          {
-            status = false;
             break;
          }
       }
@@ -712,8 +730,6 @@ bool ossimWriter::writeSMinSMaxTiffTags( const vector<ossim_float64>& minBands,
    return status;
 }
 
-
-
 template <class T>
 void ossimWriter::writeTiffTag(
    ossim_uint16 tag, ossim_uint16 type, ossim_uint64 count,
@@ -762,25 +778,58 @@ bool ossimWriter::writeTiffTilesBandSeparate( std::vector<ossim_uint64>& tile_of
                                               std::vector<ossim_float64>& minBands,
                                               std::vector<ossim_float64>& maxBands )
 {
-   static const char* const MODULE = "ossimTiffWriter::writeToTilesBandSeparate";
-   if (traceDebug()) CLOG << " Entered." << std::endl;
+   static const char* const MODULE = "ossimWriter::writeToTilesBandSeparate";
+   if ( traceDebug() ) CLOG << " Entered...\n";
 
    // Start the sequence at the first tile.
    theInputConnection->setToStartOfSequence();
 
+   // Control flags:
+   bool alignTiles    = getAlignTilesFlag();
+   bool flushTiles    = getFlushTilesFlag();
+   bool writeBlanks   = getWriteBlanksFlag();
+   bool computeMinMax = needsMinMax();
+
+   // Block size for write:
+   const std::streamsize BLOCK_SIZE = getBlockSize();
+   
    const ossim_int32 BANDS       = (ossim_int32)theInputConnection->getNumberOfOutputBands();
    const ossim_int32 TILES_WIDE  = (ossim_int32)theInputConnection->getNumberOfTilesHorizontal();
    const ossim_int32 TILES_TOTAL = (ossim_int32)theInputConnection->getNumberOfTiles();
 
+   if (traceDebug())
+   {
+      ossimNotify(ossimNotifyLevel_DEBUG)
+         << "align tiles flag:     " << alignTiles
+         << "\nflush tiles flag:     " << flushTiles
+         << "\nwrite blanks flag:    " << writeBlanks
+         << "\ncompute min max flag: " << computeMinMax
+         << "\nwrite block size:     " << BLOCK_SIZE
+         << "\nBANDS:                " << BANDS
+         << "\nTILES_WIDE:           " << TILES_WIDE
+         << "\nTILES_TOTAL:          " << TILES_TOTAL << "\n";
+   }
+
    tile_offsets.resize( TILES_TOTAL*BANDS );
    tile_byte_counts.resize( TILES_TOTAL*BANDS );
 
+   ossimDataObjectStatus tileStatus = OSSIM_STATUS_UNKNOWN;
    ossim_int64 ossimTileIndex    = 0;
    ossim_int64 tiffTileIndex     = 0;
    ossim_int64 tileSizeInBytes   = 0;
    ossim_int64 bandOffsetInBytes = 0;
-   std::streamoff startPos = m_str->tellp();
 
+   //---
+   // Adjust the starting file position to make room for IFD tags, tile offset
+   // and tile byte counts and arrays.
+   //
+   // Assuming:
+   // IFD start = 16, end 512, gives 496 bytes for tags.
+   // Array section start = 512, end is start + (16 * tile_count * bands) + 256 bytes
+   // for geotiff array bytes.
+   //---
+   std::streamsize startPos = 512 + 16 * TILES_TOTAL * BANDS + 256;
+   
    while ( ossimTileIndex < TILES_TOTAL )
    {
       ossimRefPtr<ossimImageData> id = theInputConnection->getNextTile();
@@ -793,6 +842,8 @@ bool ossimWriter::writeTiffTilesBandSeparate( std::vector<ossim_uint64>& tile_of
             << std::endl;
          return false;
       }
+
+      tileStatus = id->getDataObjectStatus();
       
       if ( ossimTileIndex == 0 )
       {
@@ -800,61 +851,101 @@ bool ossimWriter::writeTiffTilesBandSeparate( std::vector<ossim_uint64>& tile_of
          bandOffsetInBytes = tileSizeInBytes * TILES_TOTAL;
       }
 
-      // Compute running min, max.
-      id->computeMinMaxPix(minBands, maxBands);
+      if ( computeMinMax )
+      {
+         if ( (tileStatus == OSSIM_FULL) || (tileStatus == OSSIM_PARTIAL) )
+         {
+            // Compute running min, max.
+            id->computeMinMaxPix(minBands, maxBands);
+         }
+      }
       
       // Band loop.
       for (ossim_int32 band=0; band < BANDS; ++band)
       {
-         // Grab a pointer to the tile for the band.
-         const char* data = (const char*)id->getBuf(band);
+         tiffTileIndex = ossimTileIndex + band * TILES_TOTAL;
          
-         // Compress data here(future maybe, i.e. jpeg, j2k...
-
-         //---
-         // Write the tile.
-         // Note: tiles laid out, all the red tiles, all the green tiles all the
-         // blue tiles.
-         //---
-         if(data)
+         if ( (writeBlanks == true) || (tileStatus == OSSIM_FULL) || (tileStatus == OSSIM_PARTIAL) )
          {
-            // Compute the stream position:
-            std::streamoff pos = startPos + ossimTileIndex * tileSizeInBytes +
-               band * bandOffsetInBytes;
-            m_str->seekp( pos );
-
-            if ( m_str->good() )
+            // Grab a pointer to the tile for the band.
+            const char* data = (const char*)id->getBuf(band);
+            
+            // Compress data here(future maybe, i.e. jpeg, j2k...
+            
+            //---
+            // Write the tile.
+            // Note: tiles laid out, all the red tiles, all the green tiles all the
+            // blue tiles.
+            //---
+            if(data)
             {
-               tiffTileIndex = ossimTileIndex + band * TILES_TOTAL;
-               tile_offsets[ tiffTileIndex ] = (ossim_uint64)pos;
-               tile_byte_counts[ tiffTileIndex ] = (ossim_uint64)tileSizeInBytes;
+               // Compute the stream position:
+               std::streampos pos = startPos + ossimTileIndex * tileSizeInBytes +
+                  band * bandOffsetInBytes;
+               
+               if ( alignTiles )
+               {
+                  // Snap to block boundary:
+                  std::streampos overflow = pos % BLOCK_SIZE;
+                  if ( overflow > 0 )
+                  {
+                     pos += BLOCK_SIZE - overflow;
+                  }
+               }
                
-               // Write the tile to stream:
-               m_str->write( data, (std::streamsize)tileSizeInBytes);
+               m_str->seekp( pos );
                
-               // Check stream:
-               if ( m_str->fail() == true )
+               if ( m_str->good() )
+               { 
+                  tile_offsets[ tiffTileIndex ] = (ossim_uint64)pos;
+                  tile_byte_counts[ tiffTileIndex ] = (ossim_uint64)tileSizeInBytes;
+
+                  // Write the tile to stream:
+                  m_str->write( data, (std::streamsize)tileSizeInBytes);
+
+                  if ( flushTiles )
+                  {
+                     m_str->flush();
+                  }
+                  
+                  // Check stream:
+                  if ( m_str->fail() == true )
+                  {
+                     ossimNotify(ossimNotifyLevel_DEBUG)
+                        << MODULE << " ERROR:\nWrite error on tiff tile:  " << ossimTileIndex
+                        << std::endl;
+                     return false;
+                  }
+               }
+               else
                {
                   ossimNotify(ossimNotifyLevel_DEBUG)
-                     << MODULE << " ERROR:\nWrite error on tiff tile:  " << ossimTileIndex
-                     << std::endl;
+                     << MODULE << " ERROR:\nStream has gone bad!" << std::endl;
                   return false;
                }
+               
             }
             else
             {
-               ossimNotify(ossimNotifyLevel_DEBUG)
-                  << MODULE << " ERROR:\nStream has gone bad!" << std::endl;
+               ossimNotify(ossimNotifyLevel_WARN)
+                  << MODULE << " ERROR:\nNull input tile:  " << ossimTileIndex
+                  << std::endl;
                return false;
             }
-
          }
          else
          {
-            ossimNotify(ossimNotifyLevel_WARN)
-               << MODULE << " ERROR:\nNull input tile:  " << ossimTileIndex
-               << std::endl;
-            return false;
+            //---
+            // Writing sparse tiff.
+            // Set the offset and byte count to 0 to indicate blank tile.
+            //---
+            if (traceDebug())
+            {
+               ossimNotify(ossimNotifyLevel_DEBUG)
+                  << "sparse blank tile[" << tiffTileIndex << "]: " << tiffTileIndex << "\n";
+            }
+            tile_offsets[ tiffTileIndex ] = 0;
+            tile_byte_counts[ tiffTileIndex ] = 0;
          }
          
       } // End of band loop.
@@ -876,7 +967,7 @@ bool ossimWriter::writeTiffTilesBandSeparate( std::vector<ossim_uint64>& tile_of
       
    } // End: while ( ossimTileIndex < TILES_TOTAL )
 
-   if (traceDebug()) CLOG << " Exited." << std::endl;
+   if ( traceDebug() ) CLOG << " Exited...\n";
    
    return m_str->good();
 }
@@ -892,6 +983,200 @@ bool ossimWriter::setOutputStream(std::ostream& stream)
    return true;
 }
 
+void ossimWriter::setTileSize(const ossimIpt& tileSize)
+{
+   if ( (tileSize.x % 16) || (tileSize.y % 16) )
+   {
+      if(traceDebug())
+      {
+         ossimNotify(ossimNotifyLevel_DEBUG)
+                  << "ossimWriter::setTileSize ERROR:"
+                  << "\nTile size must be a multiple of 16!"
+                  << "\nSize remains:  " << m_outputTileSize
+                  << std::endl;
+      }
+   }
+   else
+   {
+      m_outputTileSize = tileSize;
+
+      // For save state:
+      m_kwl->addPair( TILE_SIZE_KW, m_outputTileSize.toString().string() );
+   }
+}
+
+const ossimIpt& ossimWriter::getOutputTileSize() const
+{
+   return m_outputTileSize;
+}
+
+bool ossimWriter::saveState( ossimKeywordlist& kwl, const char* prefix) const
+{
+   // Lazy man save state...
+   kwl.add( prefix, *(m_kwl.get()), true );
+   return ossimImageFileWriter::saveState(kwl, prefix);
+}
+
+bool ossimWriter::loadState(const ossimKeywordlist& kwl, const char* prefix)
+{
+   bool result = false;
+   if ( ossimImageFileWriter::loadState(kwl, prefix) )
+   {
+      if ( theOutputImageType!="ossim_ttbs")
+      {
+         result = true;
+         
+         std::string pfx = prefix?prefix:"";  
+         std::string value;
+
+         value = kwl.findKey( pfx, ALIGN_TILES_KW );
+         if ( value.size() )
+         {
+            m_kwl->addPair( ALIGN_TILES_KW, value, true );
+         }
+
+         value = kwl.findKey( pfx, BLOCK_SIZE_KW );
+         if ( value.size() )
+         {
+            m_kwl->addPair( BLOCK_SIZE_KW, value, true );
+         }
+
+         value = kwl.findKey( pfx, FLUSH_TILES_KW );
+         if ( value.size() )
+         {
+            m_kwl->addPair( FLUSH_TILES_KW, value, true );
+         }
+
+         value = kwl.findKey( pfx, INCLUDE_BLANK_TILES_KW );
+         if ( value.size() )
+         {
+            m_kwl->addPair( INCLUDE_BLANK_TILES_KW, value, true );
+         }
+
+         value = kwl.findKey( pfx, TILE_SIZE_KW );
+         if ( value.size() )
+         {
+            m_outputTileSize.toPoint(value);
+            m_kwl->addPair( TILE_SIZE_KW, m_outputTileSize.toString().string(), true );
+         }
+      }
+   }
+
+   return result;
+}
+
+void ossimWriter::setProperty(ossimRefPtr<ossimProperty> property)
+{
+   if( property.valid() )
+   {
+      // See if it's one of our properties:
+      std::string key = property->getName().string();
+
+      if ( traceDebug() )
+      {
+         ossimString value;
+         property->valueToString(value);
+
+         ossimNotify(ossimNotifyLevel_DEBUG)
+            << "ossimWriter::setProperty DEBUG:"
+            << "\nkey:   " << key
+            << "\nvalue: " << value << "\n";
+      }
+      
+      if ( ( key == ALIGN_TILES_KW ) ||
+           ( key == BLOCK_SIZE_KW )  ||
+           ( key == FLUSH_TILES_KW ) ||
+           ( key == INCLUDE_BLANK_TILES_KW ) )
+      {
+         ossimString value;
+         property->valueToString(value);
+         m_kwl->addPair( key, value.string(), true );
+      }
+      else if ( key == TILE_SIZE_KW )
+      {
+         // Comes in as a single int, e.g.: 256
+         ossimString value;
+         property->valueToString(value);
+         m_outputTileSize.x = value.toInt32();
+         m_outputTileSize.y = m_outputTileSize.x;
+
+         // Store in keywordlist / save state as a point, e.g.: ( 256, 256 )
+         m_kwl->addPair( key,  m_outputTileSize.toString().string(), true );
+      }
+      else
+      {
+         ossimImageFileWriter::setProperty(property);
+      }
+   }
+}
+
+ossimRefPtr<ossimProperty> ossimWriter::getProperty(const ossimString& name)const
+{
+   ossimRefPtr<ossimProperty> prop = 0;
+
+   if ( name.string() == ALIGN_TILES_KW )
+   {
+      std::string value = m_kwl->findKey( ALIGN_TILES_KW );
+      ossimRefPtr<ossimBooleanProperty> boolProp =
+         new ossimBooleanProperty(name, ossimString(value).toBool());
+      prop = boolProp.get();
+   }
+   else if( name == BLOCK_SIZE_KW )
+   {
+      // Property a single int, e.g.: 4096
+      ossim_int64 blockSize = getBlockSize();
+      ossimRefPtr<ossimStringProperty> stringProp =
+         new ossimStringProperty(name, ossimString::toString(blockSize), false); // editable flag
+      prop = stringProp.get();
+   }
+   else if ( name.string() == FLUSH_TILES_KW )
+   {
+      std::string value = m_kwl->findKey( FLUSH_TILES_KW );
+      ossimRefPtr<ossimBooleanProperty> boolProp =
+         new ossimBooleanProperty(name, ossimString(value).toBool());
+      prop = boolProp.get();
+   }
+   else if ( name.string() == INCLUDE_BLANK_TILES_KW )
+   {
+      std::string value = m_kwl->findKey( INCLUDE_BLANK_TILES_KW );
+      ossimRefPtr<ossimBooleanProperty> boolProp =
+         new ossimBooleanProperty(name, ossimString(value).toBool());
+      prop = boolProp.get();
+   }
+   else if( name == TILE_SIZE_KW )
+   {
+      // Property a single int, e.g.: 256
+      ossimRefPtr<ossimStringProperty> stringProp =
+         new ossimStringProperty(name, ossimString::toString(m_outputTileSize.x), false); // editable flag
+      stringProp->setReadOnlyFlag(false);
+      stringProp->setChangeType(ossimProperty::ossimPropertyChangeType_AFFECTS_OTHERS);
+      stringProp->addConstraint(ossimString("16"));
+      stringProp->addConstraint(ossimString("32"));
+      stringProp->addConstraint(ossimString("64"));
+      stringProp->addConstraint(ossimString("128"));
+      stringProp->addConstraint(ossimString("256"));      
+      stringProp->addConstraint(ossimString("512"));      
+      stringProp->addConstraint(ossimString("1024"));      
+      stringProp->addConstraint(ossimString("2048"));
+      prop = stringProp.get();
+   }
+   else
+   {
+      prop = ossimImageFileWriter::getProperty(name);
+   }
+   return prop;
+}
+
+void ossimWriter::getPropertyNames(std::vector<ossimString>& propertyNames) const
+{
+   propertyNames.push_back(ossimString(ALIGN_TILES_KW));
+   propertyNames.push_back(ossimString(BLOCK_SIZE_KW));
+   propertyNames.push_back(ossimString(FLUSH_TILES_KW));   
+   propertyNames.push_back(ossimString(INCLUDE_BLANK_TILES_KW));
+   propertyNames.push_back(ossimString(TILE_SIZE_KW));
+   ossimImageFileWriter::getPropertyNames(propertyNames);
+}
+
 ossim_uint16 ossimWriter::getTiffSampleFormat() const
 {
    ossim_uint16 result = 0;
@@ -925,3 +1210,86 @@ ossim_uint16 ossimWriter::getTiffSampleFormat() const
 
    return result;
 }
+
+bool ossimWriter::isTiled() const
+{
+   return ( theOutputImageType == "ossim_ttbs" );
+}
+
+bool ossimWriter::getAlignTilesFlag() const
+{
+   bool result = true; // default
+   std::string value = m_kwl->findKey( ALIGN_TILES_KW );
+   if ( value.size() )
+   {
+      result = ossimString(value).toBool();
+   }
+   return result;
+}
+
+ossim_int64 ossimWriter::getBlockSize() const
+{
+   ossim_int64 result = 4096; // default
+   std::string value = m_kwl->findKey( BLOCK_SIZE_KW );
+   if ( value.size() )
+   {
+      result = ossimString(value).toInt64();
+
+      // Disallow anything not on 1024 boundary.
+      if ( result % 1024 )
+      {
+         result = 4096;
+         ossimNotify(ossimNotifyLevel_DEBUG)
+                  << "ossimWriter::getBlockSize ERROR:"
+                  << "\nBlock size MUST be a multiple of 1024!"
+                  << "\nBlock size remains:  " << result
+                  << std::endl;
+      }
+   }
+   return result;
+}
+
+bool ossimWriter::getFlushTilesFlag() const
+{
+   bool result = true; // default
+   std::string value = m_kwl->findKey( FLUSH_TILES_KW );
+   if ( value.size() )
+   {
+      result = ossimString(value).toBool();
+   }
+   return result;
+}
+
+bool ossimWriter::getWriteBlanksFlag() const
+{
+   bool result = true; // default
+   std::string value = m_kwl->findKey( INCLUDE_BLANK_TILES_KW );
+   if ( value.size() )
+   {
+      result = ossimString(value).toBool();
+   }
+   return result;
+}
+
+bool ossimWriter::needsMinMax() const
+{
+   bool result = false;
+   switch( theInputConnection->getOutputScalarType() )
+   {
+      case OSSIM_SINT16: 
+      case OSSIM_UINT32:
+      case OSSIM_FLOAT32:
+      case OSSIM_FLOAT64:
+      case OSSIM_NORMALIZED_FLOAT:
+      case OSSIM_NORMALIZED_DOUBLE:
+      {
+         result = true;
+         break;
+      }
+      default:
+      {
+         break;
+      }
+   }
+   return result;
+}
diff --git a/src/init/JsonConfig.cpp b/src/init/JsonConfig.cpp
new file mode 100644
index 0000000..841a465
--- /dev/null
+++ b/src/init/JsonConfig.cpp
@@ -0,0 +1,467 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#include <ossim/init/JsonConfig.h>
+#include <ossim/base/ossimCommon.h>
+#include <ossim/base/ossimException.h>
+#include <ossim/base/ossimPreferences.h>
+#include <ossim/base/ossimNotify.h>
+#include <ossim/base/ossimDirectory.h>
+#include <memory>
+
+using namespace std;
+
+namespace ossim
+{
+JsonParam JsonConfig::s_nullParam;
+
+JsonParam::JsonParam(const ossimString& argname,
+                   const ossimString& arglabel,
+                   const ossimString& argdescr,
+                   ParamType   argparamType,
+                   void* value)
+:  _name (argname),
+   _label (arglabel),
+   _descr (argdescr),
+   _type (argparamType),
+   _value(0)
+{
+   setValue(value);
+}
+
+JsonParam::JsonParam(const JsonParam& copy)
+:  _label (copy._label),
+   _name (copy._name),
+   _descr (copy._descr),
+   _type (copy._type),
+   _value (0)
+{
+   setValue(copy._value);
+}
+
+void JsonParam::setValue(void* value)
+{
+   if (!value)
+      return;
+
+   switch (_type)
+   {
+   case JsonParam::BOOL:
+      _value = new bool;
+      memcpy(_value, value, sizeof(bool));
+      break;
+   case JsonParam::INT:
+      _value = new int;
+      memcpy(_value, value, sizeof(int));
+      break;
+   case JsonParam::UINT:
+      _value = new unsigned int;
+      memcpy(_value, value, sizeof(unsigned int));
+      break;
+   case JsonParam::FLOAT:
+      _value = new double;
+      memcpy(_value, value, sizeof(double));
+      break;
+   case JsonParam::STRING:
+      _value = new string(*(string*)(value));
+      break;
+   case JsonParam::VECTOR:
+      _value = new vector<double>(*(vector<double>*)(value));
+      break;
+   default:
+      _value = 0;
+   }
+}
+
+void JsonParam::resetValue()
+{
+   if (!_value)
+      return;
+
+   switch (_type)
+   {
+   case JsonParam::BOOL:
+      delete (bool*)_value;
+      break;
+   case JsonParam::INT:
+   case JsonParam::UINT:
+      delete (int*)_value;
+      break;
+   case JsonParam::FLOAT:
+      delete (double*)_value;
+      break;
+   case JsonParam::STRING:
+      delete (string*)_value;
+      break;
+   case JsonParam::VECTOR:
+      ((vector<double>*)_value)->clear();
+      delete (vector<double>*)_value;
+      break;
+   default:
+      break;
+   }
+   _value = 0;
+}
+
+bool JsonParam::loadJSON(const Json::Value& paramNode)
+{
+   try
+   {
+      _name = paramNode["name"].asString();
+      _label = paramNode["label"].asString();
+      _descr = paramNode["descr"].asString();
+      Json::Value value = paramNode["value"];
+
+      ossimString ptype = paramNode["type"].asString();
+      if (ptype.empty() || _name.empty())
+         return false;
+
+      ptype.upcase();
+
+      if (ptype == "VECTOR")
+      {
+         _type = JsonParam::VECTOR;
+         vector<double> v;
+         if (value.isArray())
+         {
+            int n = value.size();
+            for (unsigned int j=0; j<n; ++j)
+               v.push_back(value[j].asDouble());
+         }
+         setValue(&v);
+      }
+      else
+      {
+         // Screen for param value list as found in the default config JSONs. Pick the first element
+         // as the default:
+         if (value.isArray())
+            value = value[0];
+
+         if (ptype == "BOOL")
+         {
+            _type = JsonParam::BOOL;
+            bool v = value.asBool();
+            setValue(&v);
+         }
+         else if (ptype == "UINT")
+         {
+            _type = JsonParam::UINT;
+            unsigned int v = value.asUInt();
+            setValue(&v);
+         }
+         else if (ptype == "INT")
+         {
+            _type = JsonParam::INT;
+            int v = value.asInt();
+            setValue(&v);
+         }
+         else if (ptype == "FLOAT")
+         {
+            _type = JsonParam::FLOAT;
+            double v = value.asDouble();
+            setValue(&v);
+         }
+         else if (ptype == "STRING")
+         {
+            _type = JsonParam::STRING;
+            string v = value.asString();
+            setValue(&v);
+         }
+      }
+   }
+   catch (exception& e)
+   {
+      ossimNotify(ossimNotifyLevel_WARN)<<"JsonParam::loadJSON() parse error encountered. Ignoring "
+            "but should check the JsonConfig JSON for parameter <"<<_name<<">."<<endl;
+      return false;
+   }
+   return true;
+}
+
+void JsonParam::saveJSON(Json::Value& paramNode) const
+{
+   vector<double>& v = *(vector<double>*)_value; // maybe not used since maybe not valid cast
+   unsigned int n = 0;
+   int i;
+   double f;
+   string s;
+   bool b;
+
+   paramNode["name"] = _name.string();
+   paramNode["label"] = _label.string();
+   paramNode["descr"] = _descr.string();
+
+   switch (_type)
+   {
+   case JsonParam::BOOL:
+      paramNode["type"] = "bool";
+      b = *(bool*)_value;
+      paramNode["value"] = b;
+      break;
+
+   case JsonParam::INT:
+      paramNode["type"] = "int";
+      i = *(int*)_value;
+      paramNode["value"] = i;
+      break;
+
+   case JsonParam::UINT:
+      paramNode["type"] = "uint";
+      n = *(unsigned int*)_value;
+      paramNode["value"] = n;
+      break;
+
+   case JsonParam::FLOAT:
+      paramNode["type"] = "float";
+      f = *(double*)_value;
+      paramNode["value"] = f;
+      break;
+
+   case JsonParam::STRING:
+      paramNode["type"] = "string";
+      s = *(string*)_value;
+      paramNode["value"] = s;
+      break;
+
+   case JsonParam::VECTOR:
+      paramNode["type"] = "vector";
+      n = v.size();
+      for (unsigned int j=0; j<n; ++j)
+         paramNode["value"][j] = v[j];
+      break;
+
+   default:
+      break;
+   }
+}
+
+bool JsonParam::asBool() const
+{
+   if (_type == BOOL)
+      return *(bool*)_value;
+   return false;
+}
+
+unsigned int JsonParam::asUint() const
+{
+   if (_type == UINT)
+      return *(unsigned int*)_value;
+   return 0;
+}
+
+int  JsonParam::asInt() const
+{
+   if ((_type == INT) || (_type == UINT))
+      return *(int*)_value;
+   return 0;
+}
+
+double JsonParam::asFloat() const
+{
+   if (_type == FLOAT)
+      return *(double*)_value;
+   return ossim::nan();
+}
+
+std::string JsonParam::asString() const
+{
+   if (_type == STRING)
+      return *(string*)_value;
+   return "";
+}
+
+void JsonParam::asVector(std::vector<double>& v) const
+{
+   v.clear();
+   if (_type == VECTOR)
+      v = *(vector<double>*)_value;
+}
+
+ostream& operator<<(std::ostream& out, const JsonParam& obj)
+{
+   Json::Value jsonNode;
+   obj.saveJSON(jsonNode);
+   out << jsonNode << endl;
+   return out;
+}
+
+//-------------------------------------------------------------
+
+JsonConfig::JsonConfig()
+{
+   // This ctor could eventually curl a spring config server for the param JSON. For now it
+   // is reading the installed share/ossim system directory for config JSON files.
+
+   // The previous parameters list is cleared first for a fresh start:
+   m_paramsMap.clear();
+   ossimFilename configFilename;
+   try
+   {
+      // First establish the directory location of the default config files:
+      ossimFilename shareName (ossimPreferences::instance()->
+         preferencesKWL().findKey( std::string( "ossim_share_directory" )));
+      if (!shareName.isDir())
+         throw ossimException("Nonexistent share drive provided for config files.");
+
+      // Fetch all JSON files:
+      ossimDirectory shareDir;
+      if (!shareDir.open(shareName))
+         throw ossimException("Share drive provided for config files is not readable.");
+      std::vector<ossimFilename> jsonFiles;
+      shareDir.findAllFilesThatMatch(jsonFiles, ".*\\.json");
+
+      // Process those that contain the "parameters" JSON node:
+      for (unsigned int i=0; i<jsonFiles.size(); i++)
+      {
+         configFilename = jsonFiles[i];
+         if (!open(configFilename))
+            throw ossimException("Bad file open or parse.");
+      }
+
+   }
+   catch (ossimException& e)
+   {
+      ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::readConfig():  Could not open/parse "
+            "config file at <"<< configFilename << ">. Error: "<<e.what()<<endl;
+   }
+}
+
+JsonConfig::JsonConfig(const ossimFilename& configFile)
+{
+   if (!open(configFile))
+      throw ossimException("Bad file open or parse.");
+}
+
+JsonConfig::~JsonConfig()
+{
+   m_paramsMap.clear();
+}
+
+bool JsonConfig::open(const ossimFilename& configFileName)
+{
+   ifstream configFile (configFileName.string());
+   if (configFile.fail())
+      return false;
+   Json::Value jsonRoot;
+   configFile >> jsonRoot;
+   if (jsonRoot.empty())
+      return false;
+   if (jsonRoot.isMember("parameters"))
+   {
+      Json::Value& paramsNode = jsonRoot["parameters"];
+      loadJSON(paramsNode);
+   }
+   configFile.close();
+   return true;
+}
+
+JsonParam& JsonConfig::getParameter(const char* paramName)
+{
+   map<string, JsonParam>::iterator i = m_paramsMap.find(string(paramName));
+   if (i != m_paramsMap.end())
+      return i->second;
+   return s_nullParam;
+}
+
+void JsonConfig::setParameter(const JsonParam& p)
+{
+   // Tricky stuff to make sure it is a deep copy of the parameter:
+   string key = p.name().string();
+   std::map<std::string, JsonParam>::iterator iter = m_paramsMap.find(key);
+   if (iter != m_paramsMap.end())
+      m_paramsMap.erase(key);
+   m_paramsMap.emplace(key, p);
+}
+
+bool JsonConfig::paramExists(const char* paramName) const
+{
+   map<string, JsonParam>::const_iterator i = m_paramsMap.find(string(paramName));
+   if (i != m_paramsMap.end())
+      return true;
+   return false;
+}
+
+void JsonConfig::loadJSON(const Json::Value& json_node)
+{
+   Json::Value paramNode;
+
+   // Support two forms: long (with full param descriptions and types), or short (just name: value)
+   if (json_node.isArray())
+   {
+      // Long form:
+      for (unsigned int i=0; i<json_node.size(); ++i)
+      {
+         paramNode = json_node[i];
+         JsonParam p;
+         if (p.loadJSON(paramNode))
+            setParameter(p);
+      }
+   }
+   else
+   {
+      // Short form expects a prior entry in the params map whose value will be overriden here:
+      Json::Value::Members members = json_node.getMemberNames();
+      for (size_t i=0; i<members.size(); ++i)
+      {
+         JsonParam& p = getParameter(members[i].c_str());
+         if (p.name().empty())
+         {
+            ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::loadJSON():  Attempted to override "
+                  "nonexistent parameter <"<< members[i] << ">. Ignoring request."<<endl;
+            continue;
+         }
+         if (p.descr().contains("DEPRECATED"))
+         {
+            ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::loadJSON()  Parameter "<<p.name()
+                  <<" "<<p.descr()<<endl;
+            continue;
+         }
+
+         // Create a full JSON representation of the named parameter from the default list, replace
+         // its value, and recreate the parameter from the updated full JSON:
+         p.saveJSON(paramNode);
+         paramNode["value"] = json_node[p.name().string()];
+         p.loadJSON(paramNode);
+     }
+   }
+}
+
+
+void JsonConfig::saveJSON(Json::Value& json_node) const
+{
+   Json::Value paramNode;
+
+   map<string, JsonParam>::const_iterator param = m_paramsMap.begin();
+   int entry = 0;
+   while (param != m_paramsMap.end())
+   {
+      param->second.saveJSON(paramNode);
+      json_node[entry++] = paramNode;
+      ++param;
+   }
+}
+
+bool JsonConfig::diagnosticLevel(unsigned int level) const
+{
+   map<string, JsonParam>::const_iterator i = m_paramsMap.find(string("diagnosticLevel"));
+   if (i != m_paramsMap.end())
+   {
+      unsigned int levelSetting = i->second.asUint();
+      return (level <= levelSetting);
+   }
+   return false;
+}
+
+std::ostream& operator<<(std::ostream& out, const JsonConfig& obj)
+{
+   Json::Value configJsonNode;
+   obj.saveJSON(configJsonNode);
+   out<<configJsonNode<<endl;
+   return out;
+}
+
+}
diff --git a/src/projection/ossimImageViewTransform.cpp b/src/projection/ossimImageViewTransform.cpp
index b8ea0f7..15e6226 100644
--- a/src/projection/ossimImageViewTransform.cpp
+++ b/src/projection/ossimImageViewTransform.cpp
@@ -306,6 +306,21 @@ ossimDrect ossimImageViewTransform::getImageToViewBounds(const ossimDrect& image
    return ossimDrect(p1, p2, p3, p4);
 }
 
+ossimDrect ossimImageViewTransform::getViewToImageBounds(const ossimDrect& viewRect)const
+{
+   ossimDpt p1;
+   ossimDpt p2;
+   ossimDpt p3;
+   ossimDpt p4;
+
+   viewToImage(viewRect.ul(), p1);
+   viewToImage(viewRect.ur(), p2);
+   viewToImage(viewRect.lr(), p3);
+   viewToImage(viewRect.ll(), p4);
+
+   return ossimDrect(p1, p2, p3, p4);
+}
+
 std::ostream& ossimImageViewTransform::print(std::ostream& out) const
 {
    return out;
diff --git a/src/projection/ossimRpcModel.cpp b/src/projection/ossimRpcModel.cpp
index 48f20f7..96ca04d 100644
--- a/src/projection/ossimRpcModel.cpp
+++ b/src/projection/ossimRpcModel.cpp
@@ -1485,8 +1485,7 @@ bool ossimRpcModel::toJSON(std::ostream& jsonStream) const
 
    Json::Value root;
    root["isd"] = ISD;
-   Json::StyledWriter writer;
-   jsonStream << writer.write(root);
+   jsonStream << root;
    return true;
 #else
    jsonStream<<"Error: JSON format not supported."<<endl;
diff --git a/src/projection/ossimSensorModel.cpp b/src/projection/ossimSensorModel.cpp
index fc131e4..2b5f772 100644
--- a/src/projection/ossimSensorModel.cpp
+++ b/src/projection/ossimSensorModel.cpp
@@ -1160,7 +1160,9 @@ void ossimSensorModel::imagingRay(const ossimDpt& image_point,
 //  
 //*****************************************************************************
 ossimSensorModel::CovMatStatus ossimSensorModel::getObsCovMat(
-   const ossimDpt& /* ipos */ , NEWMAT::SymmetricMatrix& Cov, const ossim_float64 defPointingSigma)
+      const ossimDpt& /* ipos */ ,
+      NEWMAT::SymmetricMatrix& Cov,
+      const ossim_float64 defPointingSigma) const
 {
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Mensuration error contribution
diff --git a/src/projection/ossimSensorModelTuple.cpp b/src/projection/ossimSensorModelTuple.cpp
index 0f9eaac..e2118d2 100644
--- a/src/projection/ossimSensorModelTuple.cpp
+++ b/src/projection/ossimSensorModelTuple.cpp
@@ -30,12 +30,12 @@ static const char OSSIM_ID[] = "$Id: ossimSensorModelTuple.cpp 22045 2012-12-28
 #endif
 
 ossimRpcPqeInputs::ossimRpcPqeInputs()
-   : theRpcElevationAngle(ossim::nan()),
-     theRpcAzimuthAngle(ossim::nan()),
-     theRpcBiasError(ossim::nan()),
-     theRpcRandError(ossim::nan()),
-     theSurfaceNormalVector(),
-     theSurfaceCovMatrix(3,3)
+: theRpcElevationAngle(ossim::nan()),
+  theRpcAzimuthAngle(ossim::nan()),
+  theRpcBiasError(ossim::nan()),
+  theRpcRandError(ossim::nan()),
+  theSurfaceNormalVector(),
+  theSurfaceCovMatrix(3,3)
 {
 }
 
@@ -51,24 +51,24 @@ ossimRpcPqeInputs::~ossimRpcPqeInputs()
 //*****************************************************************************
 ossimSensorModelTuple::ossimSensorModelTuple()
 :
-theNumImages(0),
-theSurfCE90(0.0),
-theSurfLE90(0.0),
-theSurfAccSet(false),
-theSurfAccRepresentsNoDEM(false),
-theRpcPqeInputs()
+      theNumImages(0),
+      theSurfCE90(0.0),
+      theSurfLE90(0.0),
+      theSurfAccSet(false),
+      theSurfAccRepresentsNoDEM(false),
+      theRpcPqeInputs()
 {
    if (traceDebug())
    {
       ossimNotify(ossimNotifyLevel_DEBUG)
-         << "\nossimSensorModelTuple::ossimSensorModelTuple DEBUG:"
-         << std::endl;
+               << "\nossimSensorModelTuple::ossimSensorModelTuple DEBUG:"
+               << std::endl;
 #ifdef OSSIM_ID_ENABLED
       ossimNotify(ossimNotifyLevel_DEBUG)
-         << "OSSIM_ID:  " << OSSIM_ID << std::endl;
+      << "OSSIM_ID:  " << OSSIM_ID << std::endl;
 #endif 
    }
-   
+
 }
 
 
@@ -79,9 +79,9 @@ theRpcPqeInputs()
 ossimSensorModelTuple::~ossimSensorModelTuple()
 {
    if (traceExec())  ossimNotify(ossimNotifyLevel_DEBUG)
-      << "DEBUG: ~ossimSensorModelTuple(): entering..." << std::endl;
+            << "DEBUG: ~ossimSensorModelTuple(): entering..." << std::endl;
    if (traceExec())  ossimNotify(ossimNotifyLevel_DEBUG)
-      << "DEBUG: ~ossimSensorModelTuple(): returning..." << std::endl;
+            << "DEBUG: ~ossimSensorModelTuple(): returning..." << std::endl;
 }
 
 
@@ -111,7 +111,7 @@ setIntersectionSurfaceAccuracy(const ossim_float64& surfCE90,
                                const ossim_float64& surfLE90)
 {
    bool setOK = false;
-   
+
    if (surfCE90>=0.0 && surfLE90>=0.0)
    {
       theSurfCE90 = surfCE90;
@@ -136,7 +136,7 @@ setIntersectionSurfaceAccuracy(const ossim_float64& surfCE90,
       theSurfAccRepresentsNoDEM = true;
       setOK = true;
    }
-   
+
    return setOK;
 }
 
@@ -192,30 +192,30 @@ intersect(const DptSet_t   obs,
       NEWMAT::ColumnVector dR(3);
       NEWMAT::Matrix B(2,3);
       NEWMAT::SymmetricMatrix W(2);
-      
+
       // Get a priori ground estimate using first point
       ossimGpt estG;
-      theImages[1]->lineSampleToWorld(obs[1], estG);
-      
+      theImages[0]->lineSampleToWorld(obs[0], estG);
+
       for (int iter=0; iter<5; iter++)
       {   
+         // cout<<"\n iter: "<<iter;
+
          N = 0.0;
          C = 0.0;
 
-   // cout<<"\n Iter: "<<iter;
          // Loop over observations
          for (int i=0; i<nImages; i++)
          {
             ossimDpt resid;
-            // if (!getGroundObsEqComponents(i, iter, obs[i], estG, resid, B, W))
             if (!getGroundObsEqComponents(i, obs[i], estG, resid, B, W))
             {
                covOK = false;
             }
-            
+
             F[0] = resid.x;
             F[1] = resid.y;
-   // cout<<"\n  F{"<<i+1<<"}: "<<F[0]<<", "<<F[1];
+            // cout<<"\n  F{"<<i+1<<"}: "<<F[0]<<", "<<F[1];
 
             // Form coefficient matrix & discrepancy vector
             BtWF << B.t() * W * F;
@@ -228,7 +228,7 @@ intersect(const DptSet_t   obs,
          Ni = invert(N);
          dR = Ni * C;
 
-   // cout<<"\n    dR: ("<<dR[0]<<", "<<dR[1]<<", "<<dR[2]<<")"<<endl;
+         // cout<<"\n    dR: ("<<dR[0]<<", "<<dR[1]<<", "<<dR[2]<<")"<<endl;
 
          // Update estimate
          double latUpd = estG.latd()   - dR[0];
@@ -239,23 +239,22 @@ intersect(const DptSet_t   obs,
          estG.lond(lonUpd);
          estG.height(hgtUpd);
 
-
          if (traceDebug())
          {
             ossimNotify(ossimNotifyLevel_DEBUG)
-               << "DEBUG: intersect:\n"
-               << "  iteration:\n" << iter
-               // << "  C:\n"  << C 
-               // << "  Ni:\n" << Ni 
-               << "  dR:\n" << dR <<std::endl;
+                     << "DEBUG: intersect:\n"
+                     << "  iteration:\n" << iter
+                     // << "  C:\n"  << C
+                     // << "  Ni:\n" << Ni
+                     << "  dR:\n" << dR <<std::endl;
          }
-      
+
       } // iterative loop
-      
+
       // Return intersected point
       ossimEcefPoint finalEst(estG);
       pt = finalEst;
-      
+
       // Return propagated covariance matrix
       if (covOK)
       {
@@ -264,14 +263,14 @@ intersect(const DptSet_t   obs,
       }
       else
          epOK = false;
-      
+
       // Set operation status
       if (epOK)
          opOK = OP_SUCCESS;
       else
          opOK = ERROR_PROP_FAIL;
    }
-   
+
    return opOK;
 }
 
@@ -291,21 +290,21 @@ intersect(const ossim_int32&   img,
 {
    IntersectStatus opOK = OP_FAIL;
    ossimGpt ptG;
-   
+
    // Intersection
    theImages[img]->lineSampleHeightToWorld(obs, atHeightAboveEllipsoid, ptG);
    ossimEcefPoint ptECF(ptG);
    pt = ptECF;
-   
+
    // Error propagation
    bool epOK = computeSingleInterCov(img, obs, ptG, AT_HGT, covMat);
-      
+
    // Set operation status
    if (epOK)
       opOK = OP_SUCCESS;
    else
       opOK = ERROR_PROP_FAIL;
-   
+
    return opOK;
 }
 
@@ -319,26 +318,26 @@ intersect(const ossim_int32&   img,
 ossimSensorModelTuple::IntersectStatus ossimSensorModelTuple::
 intersect(const ossim_int32&     img,
           const ossimDpt&        obs,
-                ossimEcefPoint&  pt,
-                NEWMAT::Matrix&  covMat)
+          ossimEcefPoint&  pt,
+          NEWMAT::Matrix&  covMat)
 {
    IntersectStatus opOK = OP_FAIL;
    ossimGpt ptG;
-   
+
    // Intersection
    theImages[img]->lineSampleToWorld(obs, ptG);
    ossimEcefPoint ptECF(ptG);
    pt = ptECF;
-   
+
    // Error propagation
    bool epOK = computeSingleInterCov(img, obs, ptG, AT_DEM, covMat);
-   
+
    // Set operation status
    if (epOK)
       opOK = OP_SUCCESS;
    else
       opOK = ERROR_PROP_FAIL;
-   
+
    return opOK;
 }
 
@@ -358,7 +357,7 @@ bool ossimSensorModelTuple::getGroundObsEqComponents(
       NEWMAT::SymmetricMatrix& W) const
 {
    // Temporary image geometry
-   ossimImageGeometry* iGeom = new ossimImageGeometry(NULL, theImages[img]);
+   ossimImageGeometry* iGeom = new ossimImageGeometry(NULL, (ossimProjection*) theImages[img].get());
 
    // Evaluate residuals
    ossimDpt computedImg;
@@ -386,11 +385,11 @@ bool ossimSensorModelTuple::getGroundObsEqComponents(
       NEWMAT::Matrix Wfull = invert(Cov);
       W << Wfull;
    }
-   
+
    bool covOK = false;
    if (covStatus == ossimSensorModel::COV_FULL)
       covOK = true;
-   
+
    return covOK;
 }
 
@@ -413,28 +412,28 @@ bool ossimSensorModelTuple::computeSingleInterCov(
    NEWMAT::SymmetricMatrix W(2);
    NEWMAT::Matrix surfCovENU(3,3);
    ossimDpt resid;
-   
+
    bool tCovOK;
    bool covOK;
-   
+
    // Set the height reference
    ossimHgtRef hgtRef(cRefType);
 
 
    if (PTR_CAST(ossimRpcModel, theImages[img]))
    {
-     ossimRpcModel* model = PTR_CAST(ossimRpcModel, theImages[img]);
+      ossimRpcModel* model = PTR_CAST(ossimRpcModel, theImages[img]);
 
-     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-     // Special case for handling RPC LOS error components
-     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      // Special case for handling RPC LOS error components
+      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       ossimGpt ptObs(obs.samp,obs.line);
       theImages[img]->getForwardDeriv(OBS_INIT, ptObs);
       resid = theImages[img]->getForwardDeriv(EVALUATE, ptG);
       ossimDpt pWRTx = theImages[img]->getForwardDeriv(P_WRT_X, ptG);
       ossimDpt pWRTy = theImages[img]->getForwardDeriv(P_WRT_Y, ptG);
       ossimDpt pWRTz = theImages[img]->getForwardDeriv(P_WRT_Z, ptG);
-     
+
       // Form required partials in local frame
       ossimLsrSpace enu(ptG);
       NEWMAT::Matrix jECF(3,2);
@@ -452,7 +451,7 @@ bool ossimSensorModelTuple::computeSingleInterCov(
       ossim_float64  dV_dx = jLSR(1,2);
       ossim_float64  dV_dy = jLSR(2,2);
       ossim_float64  dV_dz = jLSR(3,2);
-      
+
       // Compute azimuth & elevation angles
       ossim_float64 den = dU_dy*dV_dx - dV_dy*dU_dx;
       ossim_float64 dY  = dU_dx*dV_dz - dV_dx*dU_dz;
@@ -473,7 +472,7 @@ bool ossimSensorModelTuple::computeSingleInterCov(
       // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       ossim_float64 surfCE;
       ossim_float64 surfLE;
-      
+
       if (theSurfAccRepresentsNoDEM)
       {
          //***************************************************************
@@ -483,10 +482,10 @@ bool ossimSensorModelTuple::computeSingleInterCov(
          //    [2] surfLE90 contains the probability level divisor for
          //          RPC hgtScale to yield a 1-sigma value
          //***************************************************************
-         
+
          // Reset the surface normal to vertical
          surfN = surfN.zAligned();
-         
+
          // Set approximate surface CE/LE based on RPC parameters
          //  [1] Assume range (scale) only to be 90% vertical error for now
          //  [2] Assume bias could be used for height
@@ -497,23 +496,23 @@ bool ossimSensorModelTuple::computeSingleInterCov(
          ossim_float64 scaledHgtRng = abs(hgtRng/theSurfCE90);
          ossim_float64 scaled1SigmaHgtRng = abs(scaledHgtRng/theSurfLE90);
          surfLE = scaled1SigmaHgtRng*1.6449;
-         
+
          if(traceDebug())
          {
             ossimNotify(ossimNotifyLevel_INFO)
-               << "\n computeSingleInterCov() RPC NoDEM state selected..."
-               << "\n   RPC Height Scale = " << rpcPar.hgtScale <<" m"
-               << "\n    Scale Divisor   = " <<abs(theSurfCE90)
-               << "\n    1-Sigma Divisor = "<<abs(theSurfLE90)
-               << std::endl;
-          }
-     }
+                     << "\n computeSingleInterCov() RPC NoDEM state selected..."
+                     << "\n   RPC Height Scale = " << rpcPar.hgtScale <<" m"
+                     << "\n    Scale Divisor   = " <<abs(theSurfCE90)
+                     << "\n    1-Sigma Divisor = "<<abs(theSurfLE90)
+                     << std::endl;
+         }
+      }
       else
       {
          surfCE = theSurfCE90;
          surfLE = theSurfLE90;
       }
-      
+
       tCovOK = hgtRef.getSurfaceCovMatrix(surfCE, surfLE, surfCovENU);
 
       // Evaluate & retrieve the ENU covariance matrix
@@ -526,25 +525,25 @@ bool ossimSensorModelTuple::computeSingleInterCov(
          theRpcPqeInputs.theRpcRandError        = model->getRandError();
          theRpcPqeInputs.theSurfaceNormalVector = surfN;
          theRpcPqeInputs.theSurfaceCovMatrix    = surfCovENU;
-         
-          if(traceDebug())
-          {
-             ossimNotify(ossimNotifyLevel_INFO)
-                        << "\n RPC error prop parameters..."
-                        << "\n   Elevation Angle  = " << tEl*DEG_PER_RAD<< " deg"
-                        << "\n   Azimuth Angle    = " << tAz*DEG_PER_RAD<<" deg"
-                        << "\n   RPC Bias Error   = " <<model->getBiasError() <<" m"
-                        << "\n   RPC Random Error = " <<model->getRandError()<<" m"
-                        << "\n            surfN   = " <<surfN
-                        << "\n       surfCovENU   = \n" <<surfCovENU
-                        << std::endl;
-          }        
+
+         if(traceDebug())
+         {
+            ossimNotify(ossimNotifyLevel_INFO)
+                              << "\n RPC error prop parameters..."
+                              << "\n   Elevation Angle  = " << tEl*DEG_PER_RAD<< " deg"
+                              << "\n   Azimuth Angle    = " << tAz*DEG_PER_RAD<<" deg"
+                              << "\n   RPC Bias Error   = " <<model->getBiasError() <<" m"
+                              << "\n   RPC Random Error = " <<model->getRandError()<<" m"
+                              << "\n            surfN   = " <<surfN
+                              << "\n       surfCovENU   = \n" <<surfCovENU
+                              << std::endl;
+         }
 
          ossimEcefPoint pt(ptG);
-         
+
          ossimPositionQualityEvaluator qev
-            (pt,model->getBiasError(),model->getRandError(),
-             tEl,tAz,surfN,surfCovENU);
+         (pt,model->getBiasError(),model->getRandError(),
+          tEl,tAz,surfN,surfCovENU);
          NEWMAT::Matrix covENU(3,3);
          covOK = qev.getCovMatrix(covENU);
 
@@ -559,7 +558,7 @@ bool ossimSensorModelTuple::computeSingleInterCov(
          covOK = false;
       }
    }
-   
+
    else
    {
       // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -577,18 +576,18 @@ bool ossimSensorModelTuple::computeSingleInterCov(
       // is fully supported, the following call should be used.
       // hgtRef.getHeightCovMatrix(ptG, St);
       // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-      
+
       // Check for special case of "no DEM" error propagation, only used for RPC
       if (theSurfAccRepresentsNoDEM)
       {
          if(traceDebug())
          {
             ossimNotify(ossimNotifyLevel_INFO)
-               << "\n computeSingleInterCov() RPC NoDEM state selected..."
-               << " Not valid for this sensor model" << std::endl;
+                     << "\n computeSingleInterCov() RPC NoDEM state selected..."
+                     << " Not valid for this sensor model" << std::endl;
          }
       }
-      
+
       if (hgtRef.getSurfaceCovMatrix(theSurfCE90, theSurfLE90, surfCovENU))
       {
          tCovOK = hgtRef.getSurfaceNormalCovMatrix(ptG, surfCovENU, St);
@@ -597,7 +596,7 @@ bool ossimSensorModelTuple::computeSingleInterCov(
       {
          tCovOK = false;
       }
-         
+
       if (tCovOK)
       {
          NEWMAT::Matrix Sti = invert(St);
@@ -610,7 +609,7 @@ bool ossimSensorModelTuple::computeSingleInterCov(
          covMat = invert(BtWB);
       }
    }
-   
+
    return covOK;
 }
 
@@ -630,7 +629,7 @@ NEWMAT::Matrix ossimSensorModelTuple::invert(const NEWMAT::Matrix& m) const
 
    // decompose m.t*m into the singular values and vectors.
    NEWMAT::SVD(m, d, u, v, true, true);
-   
+
    // invert the diagonal
    for(idx=0; idx < (ossim_uint32)d.Ncols(); ++idx)
    {
@@ -644,9 +643,9 @@ NEWMAT::Matrix ossimSensorModelTuple::invert(const NEWMAT::Matrix& m) const
          if (traceDebug())
          {
             ossimNotify(ossimNotifyLevel_WARN)
-               << "DEBUG: ossimSensorModelTuple::invert(): "
-               << "\nsingular matrix in SVD..."
-               << std::endl;
+                     << "DEBUG: ossimSensorModelTuple::invert(): "
+                     << "\nsingular matrix in SVD..."
+                     << std::endl;
          }
       }
    }
diff --git a/src/reg/GroundControlPoint.cpp b/src/reg/GroundControlPoint.cpp
new file mode 100644
index 0000000..48cee88
--- /dev/null
+++ b/src/reg/GroundControlPoint.cpp
@@ -0,0 +1,121 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#include <ossim/reg/GroundControlPoint.h>
+#include <ossim/base/ossimException.h>
+#include <ossim/base/ossimGpt.h>
+
+namespace ossim
+{
+
+GroundControlPoint::GroundControlPoint()
+{
+
+}
+
+GroundControlPoint::GroundControlPoint(const Json::Value& json_node)
+:  m_covariance (3)
+{
+   m_covariance.ReSize(3);
+   loadJSON(json_node);
+}
+
+
+GroundControlPoint::~GroundControlPoint()
+{
+
+}
+
+void GroundControlPoint::loadJSON(const Json::Value& json_node)
+{
+   ostringstream xmsg;
+   xmsg<<__FILE__<<": ";
+
+   m_id = json_node["gcpId"].asString();
+   if (m_id.empty())
+      m_id = json_node["pointId"].asString();
+
+   if (json_node.isMember("lat") && json_node.isMember("lon") && json_node.isMember("hgt"))
+   {
+      ossimGpt refGpt;
+      refGpt.lat = json_node["lat"].asDouble();
+      refGpt.lon = json_node["lon"].asDouble();
+      refGpt.hgt = json_node["hgt"].asDouble();
+      m_gcp = ossimEcefPoint(refGpt);
+   }
+   else if (json_node.isMember("x") && json_node.isMember("y") && json_node.isMember("z"))
+   {
+      m_gcp.x() = json_node["x"].asDouble();
+      m_gcp.y() = json_node["y"].asDouble();
+      m_gcp.z() = json_node["z"].asDouble();
+   }
+   else
+   {
+      xmsg<<"Ground point coordinates JSON not correct. JSON: \n"<<json_node.toStyledString()<<endl;
+      throw ossimException(xmsg.str());
+   }
+
+   const Json::Value& covariance = json_node["covariance"];
+   unsigned int covSize = covariance.size();
+   if ((covSize != 6) || (covSize != 9))
+   {
+      xmsg<<"No covariance information in JSON or not correctly formatted (must be 6 or 9 element array)";
+      throw ossimException(xmsg.str());
+   }
+
+   // TODO: Covariance in proper coordinate system. ENU -> ECF conversion needed here?
+   if (covSize == 6)
+   {
+      m_covariance(0,0) = covariance[0].asDouble();
+      m_covariance(1,1) = covariance[1].asDouble();
+      m_covariance(2,2) = covariance[2].asDouble();
+      m_covariance(0,1) = covariance[3].asDouble();
+      m_covariance(0,2) = covariance[4].asDouble();
+      m_covariance(1,2) = covariance[5].asDouble();
+   }
+   else
+   {
+      m_covariance(0,0) = covariance[0].asDouble();
+      m_covariance(0,1) = covariance[1].asDouble();
+      m_covariance(0,2) = covariance[2].asDouble();
+      m_covariance(1,0) = covariance[3].asDouble();
+      m_covariance(1,1) = covariance[4].asDouble();
+      m_covariance(1,2) = covariance[5].asDouble();
+      m_covariance(2,0) = covariance[6].asDouble();
+      m_covariance(2,1) = covariance[7].asDouble();
+      m_covariance(2,2) = covariance[8].asDouble();
+   }
+
+   // TODO: Implement GCP cross-correlation
+   if (json_node.isMember("crossCovariances") || json_node.isMember("gpCrossCovList"))
+   {
+      ossimNotify(ossimNotifyLevel_WARN)<<"GCP cross covariances are specified in the JSON, but the"
+         " capability is not yet implemented!"<<endl;
+   }
+}
+
+void GroundControlPoint::saveJSON(Json::Value& json_node) const
+{
+   // ID
+   json_node["gcpId"] = m_id;
+
+   // ECF
+   json_node["X"] = m_gcp.x();
+   json_node["Y"] = m_gcp.y();
+   json_node["Z"] = m_gcp.z();
+
+   Json::Value covJson (Json::arrayValue);
+   covJson[0] = m_covariance(1,1);
+   covJson[1] = m_covariance(2,2);
+   covJson[2] = m_covariance(3,3);
+   covJson[3] = m_covariance(1,2);
+   covJson[4] = m_covariance(1,3);
+   covJson[5] = m_covariance(2,3);
+
+   json_node["covariance"] = covJson;
+}
+} // end namespace ossimMsp
diff --git a/src/reg/Image.cpp b/src/reg/Image.cpp
new file mode 100644
index 0000000..6fa6ad1
--- /dev/null
+++ b/src/reg/Image.cpp
@@ -0,0 +1,115 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#include <ossim/reg/Image.h>
+#include <ossim/base/ossimException.h>
+#include <ossim/base/ossimString.h>
+#include <ossim/projection/ossimProjectionFactoryRegistry.h>
+
+using namespace std;
+
+namespace ossim
+{
+
+Image::Image(const std::string& imageId,
+             const std::string& filename,
+             const std::string& modelName,
+             unsigned int entryIndex,
+             unsigned int band)
+:  m_imageId (imageId),
+   m_filename (filename),
+   m_entryIndex (entryIndex),
+   m_activeBand (band),
+   m_modelName (modelName)
+{
+
+}
+
+Image::Image(const Json::Value& json_node)
+:  m_entryIndex (0)
+{
+   loadJSON(json_node);
+}
+
+Image::~Image()
+{
+   //m_handler.reset();
+}
+
+void Image::getAvailableModels(std::vector< pair<string, string> >& availableModels) const
+{
+   ossimProjection* proj = ossimProjectionFactoryRegistry::instance()->
+         createProjection(m_filename, m_entryIndex);
+   if (proj)
+   {
+      availableModels.push_back(pair<string, string>("OSSIM", proj->getLongName().string()));
+      delete proj;
+   }
+}
+
+void Image::loadJSON(const Json::Value& json_node)
+{
+   ostringstream xmsg;
+   xmsg<<__FILE__<<": loadJSON(JSON) -- ";
+
+   // Parse JSON. Filename is required:
+   if (json_node.isMember("filename"))
+   {
+      ossimFilename imageFile = json_node["filename"].asString();
+      m_filename = imageFile.expand(); // allow embedded environment variables
+   }
+   else
+   {
+      xmsg<<"JSON node missing required field: \"filename\".";
+      throw ossimException(xmsg.str());
+   }
+
+   // Entry index defaults to 0 if not present:
+   if (json_node["entryIndex"].isUInt())
+      m_entryIndex = json_node["entryIndex"].asUInt();
+
+   // Band defaults to 1 if not present:
+   if (json_node["band"].isUInt())
+      m_activeBand = json_node["band"].asUInt();
+
+   // Sensor model defaults to most accurate available if not provided (indicated by blank name):
+   if (json_node.isMember("sensorModel"))
+      m_modelName = json_node["sensorModel"].asString();
+
+   // Sensor model defaults to most accurate available if not provided (indicated by blank name):
+   if (json_node.isMember("imageId"))
+      m_imageId = json_node["imageId"].asString();
+
+   // Establish the sensor model. This also sets the official image ID, which will be overwritten
+   // if JSON field provided
+   string modelState = json_node["modelState"].asString();
+   ossimKeywordlist kwl;
+   kwl.parseString(modelState);
+   ossimProjection* proj =  ossimProjectionFactoryRegistry::instance()->createProjection(kwl);
+   m_sensorModel = dynamic_cast<ossimSensorModel*>(proj);
+}
+
+void Image::saveJSON(Json::Value& json_node) const
+{
+   json_node.clear();
+   json_node["imageId"] = m_imageId;
+   json_node["filename"] = m_filename.string();
+   json_node["entryIndex"] = m_entryIndex;
+
+   if (m_modelName.size())
+      json_node["sensorModel"] = m_modelName;
+
+   if (m_sensorModel.valid())
+   {
+      ossimKeywordlist kwl;
+      m_sensorModel->saveState(kwl);
+      json_node["modelState"] = kwl.toString().string();
+   }
+}
+
+
+} // end namespace 
diff --git a/src/reg/PhotoBlock.cpp b/src/reg/PhotoBlock.cpp
new file mode 100644
index 0000000..fc297c1
--- /dev/null
+++ b/src/reg/PhotoBlock.cpp
@@ -0,0 +1,183 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#include <ossim/reg/PhotoBlock.h>
+#include <ossim/base/ossimException.h>
+
+namespace ossim
+{
+PhotoBlock::PhotoBlock()
+{
+}
+
+PhotoBlock::PhotoBlock(const Json::Value& pb_json_node)
+{
+   loadJSON(pb_json_node);
+}
+
+PhotoBlock::PhotoBlock(const PhotoBlock& copyThis)
+: m_imageList (copyThis.m_imageList),
+  m_tiePointList (copyThis.m_tiePointList)
+{
+   *this = copyThis;
+}
+
+PhotoBlock::~PhotoBlock()
+{
+   m_imageList.clear();
+   m_tiePointList.clear();
+}
+
+PhotoBlock& PhotoBlock::operator=(const PhotoBlock& copythis)
+{
+   m_imageList = copythis.m_imageList;
+   m_tiePointList = copythis.m_tiePointList;
+   m_gcpList = copythis.m_gcpList;
+   return *this;
+}
+
+// TODO: Add of individual components not available until proper management of the JCM can be
+//       provided
+unsigned int  PhotoBlock::addImage(shared_ptr<Image> image)
+{
+   unsigned int last_idx = m_imageList.size();
+   m_imageList.push_back(image);
+   return last_idx;
+}
+
+unsigned int  PhotoBlock::addGroundPoint(shared_ptr<GroundControlPoint> gcp)
+{
+   unsigned int last_idx = m_gcpList.size();
+   m_gcpList.push_back(gcp);
+   return last_idx;
+}
+
+unsigned int PhotoBlock::addTiePoint(shared_ptr<TiePoint> tiepoint)
+{
+   unsigned int index = m_tiePointList.size();
+   m_tiePointList.push_back(tiepoint);
+   return index;
+}
+
+void PhotoBlock::addTiePoints(TiePointList& tiepointList)
+{
+   for (size_t i=0; i<tiepointList.size(); ++i)
+   {
+      addTiePoint(tiepointList[i]);
+   }
+}
+
+shared_ptr<Image> PhotoBlock::getImage(const std::string& imageId)
+{
+   std::shared_ptr<Image> result;
+   for (size_t i=0; i<m_imageList.size(); ++i)
+   {
+      if (m_imageList[i]->getImageId() == imageId)
+      {
+         result = m_imageList[i];
+         break;
+      }
+   }
+   return result;
+}
+
+shared_ptr<GroundControlPoint> PhotoBlock::getGroundPoint(const std::string& gcpId)
+{
+   std::shared_ptr<GroundControlPoint> result;
+   for (size_t i=0; i<m_gcpList.size(); ++i)
+   {
+      if (m_gcpList[i]->getId() == gcpId)
+      {
+         result = m_gcpList[i];
+         break;
+      }
+   }
+   return result;
+}
+
+shared_ptr<TiePoint> PhotoBlock::getTiePoint(unsigned int tpId)
+{
+   std::shared_ptr<TiePoint> result;
+   for (size_t i=0; i<m_tiePointList.size(); ++i)
+   {
+      if (m_tiePointList[i]->getTiePointId() == tpId)
+      {
+         result = m_tiePointList[i];
+         break;
+      }
+   }
+   return result;
+}
+
+void PhotoBlock::loadJSON(const Json::Value& pb_json_node)
+{
+   // Always do images first, as tiepoints will be using the image list to correct image ID:
+   if (pb_json_node.isMember("images"))
+   {
+      const Json::Value& listJson = pb_json_node["images"];
+      unsigned int count = listJson.size();
+      for (unsigned int i=0; i<count; ++i)
+      {
+         const Json::Value& jsonItem = listJson[i];
+         shared_ptr<Image> item (new Image(jsonItem));
+         m_imageList.push_back(item);
+      }
+   }
+
+   if (pb_json_node.isMember("groundPoints"))
+   {
+      const Json::Value& listJson = pb_json_node["groundPoints"];
+      unsigned int count = listJson.size();
+      for (unsigned int i=0; i<count; ++i)
+      {
+         const Json::Value& jsonItem = listJson[i];
+         shared_ptr<GroundControlPoint> item (new GroundControlPoint(jsonItem));
+         m_gcpList.push_back(item);
+      }
+   }
+
+   if (pb_json_node.isMember("tiePoints"))
+   {
+      const Json::Value& listJson = pb_json_node["tiePoints"];
+      unsigned int count = listJson.size();
+      for (unsigned int i=0; i<count; ++i)
+      {
+         const Json::Value& jsonItem = listJson[i];
+         shared_ptr<TiePoint> item (new TiePoint(jsonItem));
+         m_tiePointList.push_back(item);
+      }
+   }
+}
+
+void PhotoBlock::saveJSON(Json::Value& pbJSON) const
+{
+   Json::Value imageListJson (Json::arrayValue);
+   unsigned int count = m_imageList.size();
+   for (unsigned int i=0; i<count; ++i)
+   {
+      m_imageList[i]->saveJSON(imageListJson[i]);
+   }
+   pbJSON["images"] = imageListJson;
+
+   Json::Value gcpListJson (Json::arrayValue);
+   count = m_gcpList.size();
+   for (unsigned int i=0; i<count; ++i)
+   {
+      m_gcpList[i]->saveJSON(gcpListJson[i]);
+   }
+   pbJSON["groundPoints"] = gcpListJson;
+
+   Json::Value tpListJson (Json::arrayValue);
+   count = m_tiePointList.size();
+   for (unsigned int i=0; i<count; ++i)
+   {
+      m_tiePointList[i]->saveJSON(tpListJson[i]);
+   }
+   pbJSON["tiePoints"] = tpListJson;
+}
+
+} // end namespace
diff --git a/src/reg/TiePoint.cpp b/src/reg/TiePoint.cpp
new file mode 100644
index 0000000..8b0a885
--- /dev/null
+++ b/src/reg/TiePoint.cpp
@@ -0,0 +1,243 @@
+//**************************************************************************************************
+//
+//     OSSIM Open Source Geospatial Data Processing Library
+//     See top level LICENSE.txt file for license information
+//
+//**************************************************************************************************
+
+#include <ossim/reg/TiePoint.h>
+#include <ossim/base/ossimException.h>
+#include <ctime>
+
+using namespace std;
+
+namespace ossim
+{
+int TiePoint::s_runningId = 1;
+
+TiePoint::TiePoint()
+:  m_type (UNASSIGNED),
+   m_gsd (0.0)
+{
+
+}
+
+TiePoint::TiePoint(const TiePoint& copy)
+:  m_type (copy.m_type),
+   m_gsd (copy.m_gsd),
+   m_gcpId (copy.m_gcpId)
+{
+   for (size_t i=0; i<copy.m_images.size(); ++i)
+      m_images.push_back(copy.m_images[i]);
+
+   for (size_t i=0; i<copy.m_imagePoints.size(); ++i)
+      m_imagePoints.push_back(copy.m_imagePoints[i]);
+
+   for (size_t i=0; i<copy.m_covariances.size(); ++i)
+      m_covariances.push_back(copy.m_covariances[i]);
+}
+
+TiePoint::TiePoint(const Json::Value& json_node)
+:  m_type (UNASSIGNED),
+   m_gsd (0.0)
+{
+   loadJSON(json_node);
+}
+
+TiePoint::~TiePoint()
+{
+   m_images.clear();
+   m_imagePoints.clear();
+   m_covariances.clear();
+}
+
+void TiePoint::setTiePointId(const string& id)
+{
+   if (id.empty())
+   {
+      // Generate ID based on date/time:
+      ostringstream tp1;
+      tp1<<"TP"<<s_runningId++;
+      m_tiePointId = tp1.str();
+   }
+   else
+   {
+      // Only accept if there is no ID existing:
+      m_tiePointId = id;
+   }
+}
+
+void TiePoint::getImagePoint(unsigned int index,
+                             std::string& imageId,
+                             ossimDpt& imagePoint,
+                             NEWMAT::SymmetricMatrix& cov) const
+{
+   // Search the PB index list for entry:
+   imagePoint.makeNan();
+   imageId.clear();
+
+   if (index >= m_images.size())
+      return;
+
+   imageId = m_images[index]->getImageId();
+   imagePoint = m_imagePoints[index];
+   cov = m_covariances[index];
+}
+
+void TiePoint::setImagePoint(std::shared_ptr<Image> image,
+                             const ossimDpt& imagePoint,
+                             const NEWMAT::SymmetricMatrix& cov)
+{
+   bool found = false;
+
+   // Possible edit of existing point?
+   for (size_t i=0; i<m_images.size(); ++i)
+   {
+      if (m_images[i]->getImageId().compare(image->getImageId()) == 0)
+      {
+         found = true;
+         if (i >= m_imagePoints.size())
+         {
+            // This shouldn't happen, but go ahead and resize for this image:
+            m_imagePoints.resize(i+1);
+            m_covariances.resize(i+1);
+         }
+         m_imagePoints[i] = imagePoint;
+         m_covariances[i] = cov;
+         break;
+      }
+   }
+
+   if (!found)
+   {
+      m_images.push_back(image);
+      m_imagePoints.push_back(imagePoint);
+      m_covariances.push_back(cov);
+   }
+}
+
+void TiePoint::setGcpId(const std::string& id)
+{
+   m_gcpId = id;
+   m_type = GCP;
+}
+
+void TiePoint::loadJSON(const Json::Value& json_node)
+{
+   ostringstream xmsg;
+   xmsg<<__FILE__<<": TiePoint(JSON) --";
+
+   // ID
+   setTiePointId(json_node["id"].asString());
+
+   // Type
+   string tpType = json_node["type"].asString();
+   switch (tpType[0])
+   {
+   case 'M':
+      m_type = TiePoint::MANUAL;
+      break;
+   case 'A':
+      m_type = TiePoint::AUTO;
+      break;
+   case 'G':
+      m_type = TiePoint::GCP;
+      break;
+   default:
+      xmsg<<"Tiepoint JSON field \"type\" must be specified as 'M', 'A', or 'G'.";
+      throw ossimException(xmsg.str());
+   }
+
+   // Read the GCP ID if present:
+   if (m_type == TiePoint::GCP)
+      m_gcpId = json_node["gcpId"].asString();
+
+   // Image points
+   const Json::Value& imagePoints = json_node["imagePoints"];
+   if (!imagePoints || (imagePoints.size() < 1))
+   {
+      xmsg<<"Tiepoint JSON field \"imagePoints\" not found or is empty!";
+      throw ossimException(xmsg.str());
+   }
+
+   // Loop over points on each image:
+   for (int i=0; i<imagePoints.size(); ++i)
+   {
+      const Json::Value& p = imagePoints[i];
+      if (!p || !(p["imageId"].isString()) || !(p["x"]) || !(p["y"]) || (p["covariance"].size()!=3))
+      {
+         xmsg<<"Tiepoint JSON field \"imagePoints\" entry is ill-formed or not complete:\n"
+               <<p.toStyledString()<<endl;
+         throw ossimException(xmsg.str());
+      }
+
+      string imageId = p["imageId"].asString();
+      string filename = p["filename"].asString();
+      shared_ptr<Image> image (new Image(imageId, filename));
+      m_images.push_back(image);
+
+      ossimDpt xy(p["x"].asDouble(), p["y"].asDouble());
+      m_imagePoints.push_back(xy);
+
+      const Json::Value& covariance = p["covariance"];
+      NEWMAT::SymmetricMatrix c (2);
+      c(1,1) = covariance[0].asDouble();
+      c(2,2) = covariance[1].asDouble();
+      c(1,2) = covariance[2].asDouble();
+      m_covariances.push_back(c);
+   }
+}
+
+void TiePoint::saveJSON(Json::Value& json_node) const
+{
+   // ID
+   json_node["id"] = m_tiePointId;
+
+   // Type
+   string tpType = json_node["type"].asString();
+   switch (m_type)
+   {
+   case TiePoint::MANUAL:
+      json_node["type"] = "M";
+      break;
+   case TiePoint::AUTO:
+      json_node["type"] = "A";
+      break;
+   case TiePoint::GCP:
+      json_node["type"] = "G";
+      break;
+   default:
+      json_node["type"] = "UNNASSIGNED";
+   }
+
+   // Image points
+   Json::Value jsonList (Json::arrayValue);
+   // Loop over points on each image:
+   for (int i=0; i<m_imagePoints.size(); ++i)
+   {
+      jsonList[i]["filename"] = m_images[i]->getFilename();
+      jsonList[i]["imageId"] = m_images[i]->getImageId();
+      jsonList[i]["x"] = m_imagePoints[i].x;
+      jsonList[i]["y"] = m_imagePoints[i].y;
+
+      if (i<m_covariances.size())
+      {
+         Json::Value covJson (Json::arrayValue);
+         covJson[0] = m_covariances[i](1,1);
+         covJson[1] = m_covariances[i](2,2);
+         covJson[2] = m_covariances[i](1,2);
+         jsonList[i]["covariance"] = covJson;
+      }
+   }
+   json_node["imagePoints"] = jsonList;
+}
+
+std::ostream& TiePoint::print(std::ostream& out) const
+{
+   Json::Value node;
+   saveJSON(node);
+   out << node.toStyledString();
+   return out;
+}
+
+} // end namespace ISA
diff --git a/src/support_data/ossimQuickbirdRpcHeader.cpp b/src/support_data/ossimQuickbirdRpcHeader.cpp
index 69fefb4..24fdcc3 100644
--- a/src/support_data/ossimQuickbirdRpcHeader.cpp
+++ b/src/support_data/ossimQuickbirdRpcHeader.cpp
@@ -53,6 +53,18 @@ std::ostream& operator << (std::ostream& out,
 
 
 ossimQuickbirdRpcHeader::ossimQuickbirdRpcHeader()
+:  theErrBias(0),
+   theErrRand(0),
+   theLineOffset(0),
+   theSampOffset(0),
+   theLatOffset(0),
+   theLonOffset(0),
+   theHeightOffset(0),
+   theLineScale(0),
+   theSampScale(0),
+   theLatScale(0),
+   theLonScale(0),
+   theHeightScale(0)
 {
 }
 
diff --git a/src/util/ossimTool.cpp b/src/util/ossimTool.cpp
index d531462..c081b95 100644
--- a/src/util/ossimTool.cpp
+++ b/src/util/ossimTool.cpp
@@ -97,11 +97,6 @@ void ossimTool::initialize(const ossimKeywordlist& kwl)
    m_kwl = kwl;
 }
 
-void ossimTool::initialize(const std::string& request)
-{
-   m_helpRequested = false;
-}
-
 void ossimTool::getKwlTemplate(ossimKeywordlist& kwl)
 {
    ossimFilename share_dir = ossimPreferences::instance()->

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/ossim.git



More information about the Pkg-grass-devel mailing list