GeoTessCPP  2.0.0
Software to facilitate storage and retrieval of 3D information about the Earth.
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines
include/GeoTessProfileNPoint.h
Go to the documentation of this file.
00001 //- ****************************************************************************
00002 //- 
00003 //- Copyright 2009 Sandia Corporation. Under the terms of Contract
00004 //- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00005 //- retains certain rights in this software.
00006 //- 
00007 //- BSD Open Source License.
00008 //- All rights reserved.
00009 //- 
00010 //- Redistribution and use in source and binary forms, with or without
00011 //- modification, are permitted provided that the following conditions are met:
00012 //- 
00013 //-    * Redistributions of source code must retain the above copyright notice,
00014 //-      this list of conditions and the following disclaimer.
00015 //-    * Redistributions in binary form must reproduce the above copyright
00016 //-      notice, this list of conditions and the following disclaimer in the
00017 //-      documentation and/or other materials provided with the distribution.
00018 //-    * Neither the name of Sandia National Laboratories nor the names of its
00019 //-      contributors may be used to endorse or promote products derived from
00020 //-      this software without specific prior written permission.
00021 //- 
00022 //- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023 //- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024 //- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025 //- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00026 //- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00027 //- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00028 //- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029 //- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030 //- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031 //- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 //- POSSIBILITY OF SUCH DAMAGE.
00033 //-
00034 //- ****************************************************************************
00035 
00036 #ifndef PROFILENPOINT_OBJECT_H
00037 #define PROFILENPOINT_OBJECT_H
00038 
00039 // **** _SYSTEM INCLUDES_ ******************************************************
00040 
00041 #include <iostream>
00042 #include <string>
00043 #include <fstream>
00044 #include <sstream>
00045 
00046 // use standard library objects
00047 using namespace std;
00048 
00049 // **** _LOCAL INCLUDES_ *******************************************************
00050 
00051 #include "GeoTessUtils.h"
00052 #include "GeoTessException.h"
00053 #include "GeoTessData.h"
00054 #include "GeoTessProfile.h"
00055 #include "GeoTessProfileType.h"
00056 #include "GeoTessInterpolatorType.h"
00057 
00058 // **** _BEGIN GEOTESS NAMESPACE_ **********************************************
00059 
00060 namespace geotess {
00061 
00062 // **** _FORWARD REFERENCES_ ***************************************************
00063 
00064 class GeoTessMetaData;
00065 class IFStreamAscii;
00066 class IFStreamBinary;
00067 
00068 // **** _CLASS DEFINITION_ *****************************************************
00069 
00080 class GEOTESS_EXP_IMP GeoTessProfileNPoint : virtual public GeoTessProfile
00081 {
00082 private:
00083 
00087         int                                                                     nNodes;
00088 
00092         float*                                                  radii;
00093 
00097         GeoTessData**                                                   data;
00098 
00105         mutable double**                y2;
00106 
00114         int*                                                            pointIndices;
00115 
00119         GeoTessProfileNPoint() : GeoTessProfile(), nNodes(0), radii(NULL), data(NULL),
00120                         y2(NULL), pointIndices(NULL) {};
00121 
00126         double*                                                 spline(float* x, GeoTessData** y, int attributeIndex,
00127                         double yp1, double ypn) const;
00128 
00134         void                                                    check(int attributeIndex) const;
00135 
00136 public:
00137 
00150         GeoTessProfileNPoint(float* r, GeoTessData** dat, int size) : GeoTessProfile(), nNodes(size), radii(NULL),
00151         data(NULL), y2(NULL), pointIndices(NULL)
00152         {
00153                 radii = new float[size];
00154                 data = new GeoTessData*[size];
00155                 for (int i=0; i<size; ++i)
00156                 {
00157                         radii[i] = r[i];
00158                         data[i] = dat[i];
00159                 }
00160 
00161                 if (radii[0] > radii[size - 1])
00162                 {
00163                         ostringstream os;
00164                         os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
00165                                         << "Profile has negative thickness" << endl;
00166                         os << "radii = ";
00167                         for (int i=0; i<size; ++i)
00168                                 os << radii[i] << ", ";
00169                         os << endl;
00170                         throw GeoTessException(os, __FILE__, __LINE__, 4301);
00171                 }
00172         }
00173 
00185         GeoTessProfileNPoint(const vector<float>& r, vector<GeoTessData*>& d)
00186         : GeoTessProfile(), nNodes(r.size()), radii(NULL),
00187         data(NULL), y2(NULL), pointIndices(NULL)
00188         {
00189                 radii = new float[nNodes];
00190                 data = new GeoTessData*[nNodes];
00191                 for (int i=0; i<nNodes; ++i)
00192                 {
00193                         radii[i] = r[i];
00194                         data[i] = d[i];
00195                 }
00196 
00197                 if (r.size() != d.size())
00198                 {
00199                         ostringstream os;
00200                         os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
00201                                         << "radii.size() != data.size()" << endl;
00202                         os << "radii.size = " << r.size() << endl;
00203                         os << "data.size   = " << d.size() << endl;
00204                         throw GeoTessException(os, __FILE__, __LINE__, 4302);
00205                 }
00206 
00207                 if (radii[0] > radii[nNodes - 1])
00208                 {
00209                         ostringstream os;
00210                         os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
00211                                         << "Profile has negative thickness" << endl;
00212                         os << "radii = ";
00213                         for (int i=0; i<nNodes; ++i)
00214                                 os << radii[i] << ", ";
00215                         os << endl;
00216                         throw GeoTessException(os, __FILE__, __LINE__, 4303);
00217                 }
00218         }
00219 
00225         GeoTessProfileNPoint(float* rad, const vector<GeoTessData*>& dat);
00226 
00230         static  string                  class_name() { return "ProfileNPoint"; };
00231 
00235         virtual int                                     class_size() const
00236         { return (int) sizeof(GeoTessProfileNPoint); };
00237 
00243         virtual const GeoTessProfileType&       getType() const
00244         { return GeoTessProfileType::NPOINT; };
00245 
00249         virtual bool                            operator == (const GeoTessProfile& p) const
00250                                                                                                                                                                 {
00251                 if (!GeoTessProfile::operator==(p)) return false;
00252 
00253                 if (nNodes != p.getNRadii()) return false;
00254 
00255                 for (int i = 0; i < nNodes; ++i)
00256                         if ((radii[i] != p.getRadius(i)) ||
00257                                         (!(*(data[i]) == p.getData(i))))
00258                                 return false;
00259 
00260                 return true;
00261                                                                                                                                                                 }
00262 
00270         bool                                                            isNaN(int nodeIndex, int attributeIndex)
00271         { return data[nodeIndex]->isNaN(attributeIndex); };
00272 
00277         virtual float                           getRadius(int i) const { return radii[i]; };
00278 
00282         virtual int                                     getNRadii() const { return nNodes; };
00283 
00287         virtual int                                     getNData() const { return nNodes; };
00288 
00293         virtual float*                  getRadii()
00294         {
00295                 float* fa = new float [nNodes];
00296                 for (int i=0; i<nNodes; ++i) fa[i] = radii[i];
00297                 return fa;
00298         }
00299 
00305         virtual GeoTessData**                   getData()
00306         {
00307                 GeoTessData** da = new GeoTessData*[nNodes];
00308                 for (int i=0; i<nNodes; ++i) da[i] = data[i];
00309                 return da;
00310         }
00311 
00312 
00316         virtual GeoTessData*                            getData(int i) { return data[i]; };
00317 
00321         virtual const GeoTessData&      getData(int i) const { return *(data[i]); };
00322 
00326         virtual void                            setData(const vector<GeoTessData*>& inData);
00327 
00331         virtual void                                    setRadii(const vector<float>& newRadii)
00332         { for (int i=0; i<nNodes; ++i) radii[i] = newRadii[i]; }
00333 
00337         virtual void                            setData(int index, GeoTessData* inData)
00338         { delete data[index]; data[index] = inData; }
00339 
00343         virtual float                           getRadiusTop() const { return radii[nNodes - 1]; };
00344 
00348         virtual const GeoTessData&      getDataTop() const { return *data[nNodes - 1]; };
00349 
00353         virtual GeoTessData*                            getDataTop() { return data[nNodes - 1]; };
00354 
00358         virtual float                           getRadiusBottom() const { return radii[0]; };
00359 
00363         virtual const GeoTessData&      getDataBottom() const { return *data[0]; };
00364 
00368         virtual GeoTessData*                            getDataBottom() { return data[0]; };
00369 
00370 
00375         virtual double getValue(int attributeIndex, int radiusIndex) const
00376         {       return data[radiusIndex]->getDouble(attributeIndex); }
00377 
00384         virtual double getValueTop(int attributeIndex) const
00385         {       return data[nNodes-1]->getDouble(attributeIndex); }
00386 
00391         virtual double                  getInterpolationCoefficient(int index, double radius) const;
00392 
00397         virtual double                  getValue(const GeoTessInterpolatorType& radialType,
00398                         int attributeIndex, double radius,
00399                         bool allowRadiusOutOfRange) const;
00400 
00405         virtual int                                     getRadiusIndex(double radius, int jlo) const;
00406 
00410         virtual double                  getInterpolationCoefficient(int index, double radius,
00411                         bool allowOutOfRange) const;
00412 
00414 
00418         GeoTessProfileNPoint(IFStreamBinary& ifs, GeoTessMetaData& gtmd);
00419 
00423         GeoTessProfileNPoint(IFStreamAscii& ifs, GeoTessMetaData& gtmd);
00424 
00428         virtual                                                 ~GeoTessProfileNPoint();
00429 
00433         virtual void                            write(IFStreamBinary& ofs);
00434 
00438         virtual void                            write(IFStreamAscii& ofs);
00439 
00448         virtual int                                     findClosestRadiusIndex(double radius) const
00449         {
00450                 int i = GeoTessProfile::getRadiusIndex(radius);
00451                 return abs(radii[i+1] - radius) < abs(radii[i] - radius) ? i+1 : i;
00452         }
00453 
00461         virtual void                            setPointIndex(int nodeIndex, int pointIndex)
00462         {
00463                 if (pointIndices == NULL)
00464                 {
00465                         if (pointIndex < 0) return;
00466 
00467                         pointIndices = new int [nNodes];
00468                         for (int i = 0; i < nNodes; ++i) pointIndices[i] = -1;
00469                 }
00470                 pointIndices[nodeIndex] = pointIndex;
00471         }
00472 
00480         virtual void resetPointIndices()
00481         {
00482                 if (pointIndices != NULL)
00483                         delete[] pointIndices;
00484                 pointIndices = NULL;
00485         }
00486 
00494         virtual int                                     getPointIndex(int nodeIndex) const
00495         {       return pointIndices == NULL ? -1 : pointIndices[nodeIndex]; }
00496 
00503         virtual void                            getWeights(map<int, double>& weights,
00504                         double dkm, double radius, double hcoefficient) const
00505         {
00506                 int node = GeoTessProfile::getRadiusIndex(radius);
00507 
00508                 //TODO:  need getInterpolationCoefficient to work for cubic spline interpolator.  It currently does not.
00509 
00510                 // get coefficient at node influencing position radius
00511 
00512                 int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
00513 
00514                 double c = getInterpolationCoefficient(node, radius, true);
00515                 if (c > 0.0)
00516                 {
00517                         map<int, double>::iterator it = weights.find(pointIndex);
00518                         if (it == weights.end())
00519                                 weights[pointIndex] = dkm * hcoefficient * c;
00520                         else
00521                                 it->second += dkm * hcoefficient * c;
00522                 }
00523 
00524                 // now get coefficient at node+1  influencing position radius
00525 
00526                 c = 1.0 - c;
00527                 pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
00528                 if (c > 0.0)
00529                 {
00530                         map<int, double>::iterator it = weights.find(pointIndex);
00531                         if (it == weights.end())
00532                                 weights[pointIndex] = dkm * hcoefficient * c;
00533                         else
00534                                 it->second += dkm * hcoefficient * c;
00535                 }
00536         }
00537 
00544         virtual void                                    getCoefficients(map<int, double>& coefficients, double radius,
00545                         double horizontalCoefficient) const
00546         {
00547                 int node = GeoTessProfile::getRadiusIndex(radius);
00548 
00549                 //TODO:  need getInterpolationCoefficient to work for cubic spline interpolator.  It currently does not.
00550                 double c = getInterpolationCoefficient(node, radius, true);
00551 
00552                 int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
00553 
00554                 if (c > 0.0)
00555                         coefficients[pointIndex] = c * horizontalCoefficient;
00556 
00557                 pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
00558 
00559                 if (c < 1.0)
00560                         coefficients[pointIndex] = (1.0 - c) * horizontalCoefficient;
00561         }
00562 
00563         virtual void setInterpolationCoefficients(const GeoTessInterpolatorType& interpType,
00564                         vector<int>& nodeIndexes, vector<double>& coefficients,
00565                         double& radius, bool& allowOutOfRange)
00566         {
00567                 //TODO:  need this method to work for cubic spline interpolator.  It currently does not.
00568 
00569                 if (radius < radii[0])
00570                 {
00571                         nodeIndexes.push_back(0);
00572                         coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
00573                 }
00574                 else if (radius > radii[nNodes-1])
00575                 {
00576                         nodeIndexes.push_back(nNodes-1);
00577                         coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
00578                 }
00579                 else
00580                 {
00581                         int index = getRadiusIndex(radius, -1);
00582                         double c = ((double)radii[index + 1] - radius) /
00583                                         ((double)radii[index + 1] - (double)radii[index]);
00584                         nodeIndexes.push_back(index);
00585                         coefficients.push_back(c);
00586                         if (c < 1.)
00587                         {
00588                                 nodeIndexes.push_back(index+1);
00589                                 coefficients.push_back(1.-c);
00590                         }
00591                 }
00592         }
00593 
00597         virtual GeoTessProfile*      copy()
00598         {
00599                 GeoTessData** d = new GeoTessData* [nNodes];
00600                 float* r = new float [nNodes];
00601                 for (int i = 0; i < nNodes; ++i)
00602                 {
00603                         d[i] = data[i]->copy();
00604                         r[i] = radii[i];
00605                 }
00606                 return new GeoTessProfileNPoint(r, d, nNodes);
00607         }
00608 
00610 
00611 }; // end class ProfileNPoint
00612 
00624 inline double   GeoTessProfileNPoint::getInterpolationCoefficient(int index,  double radius) const
00625 {
00626         if (radius <= radii[index]) return 1.0;
00627         if (radius >= radii[index + 1]) return 0.0;
00628         return (radii[index + 1] - radius) / (radii[index + 1] - radii[index]);
00629 }
00630 
00643 inline double GeoTessProfileNPoint::getValue(const GeoTessInterpolatorType& radialType,
00644                 int attributeIndex, double radius, bool allowRadiusOutOfRange) const
00645 {
00646         if (!allowRadiusOutOfRange &&
00647                         ((radius < (double)radii[0]) || (radius > (double)radii[nNodes-1])))
00648                 return NaN_DOUBLE;
00649 
00650         int index = getRadiusIndex(radius, -1);
00651 
00652         double r0 = radii[index];
00653         double v0 = data[index]->getDouble(attributeIndex);
00654 
00655         if (radius <= r0) return v0;
00656 
00657         double r1 = radii[index + 1];
00658         double v1 = data[index + 1]->getDouble(attributeIndex);
00659 
00660         if (radius >= r1) return v1;
00661 
00662         double a = (r1 - radius) / (r1 - r0);
00663 
00664         double b = 1. - a;
00665         double v = a * v0 + b * v1;
00666 
00667         switch (radialType.ordinal())
00668         {
00669         case 0: // LINEAR
00670                 return  v;
00671 
00672         case 2: // CUBIC_SPLINE
00673                 check(attributeIndex);
00674                 return v + ((a * a * a - a) * y2[attributeIndex][index]
00675                                                                  + (b * b * b - b) * y2[attributeIndex][index + 1])
00676                                                                  * (r1 - r0)    * (r1 - r0) / 6.0;
00677 
00678         default:
00679                 ostringstream os;
00680                 os << endl << "ERROR in ProfileNPoint::getValue" << endl
00681                                 << "InterpolatorType: " << radialType.name()
00682                                 << " cannot be applied to a Profile." << endl
00683                                 << "Must specify LINEAR or SPLINE" << endl;
00684                 throw GeoTessException(os, __FILE__, __LINE__, 4304);
00685         }
00686 }
00687 
00689 
00695 inline void GeoTessProfileNPoint::check(int attributeIndex) const
00696 {
00697         if (y2 == NULL)
00698         {
00699                 y2 = new double* [data[0]->size()];
00700                 for (int i=0; i<data[0]->size(); ++i)
00701                         y2[i] = NULL;
00702         }
00703         if (y2[attributeIndex] == NULL)
00704                 y2[attributeIndex] = spline(radii, data, attributeIndex, 1.0e30, 1.0e30);
00705 }
00706 
00708 
00709 } // end namespace geotess
00710 
00711 #endif  // PROFILENPOINT_OBJECT_H