GeoTessCPP
2.0.0
Software to facilitate storage and retrieval of 3D information about the Earth.
|
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 "Data.h" 00054 #include "Profile.h" 00055 #include "ProfileType.h" 00056 #include "InterpolatorType.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 ProfileNPoint : virtual public Profile 00081 { 00082 private: 00083 00087 int nNodes; 00088 00092 float* radii; 00093 00097 Data** data; 00098 00105 mutable double** y2; 00106 00114 int* pointIndices; 00115 00119 ProfileNPoint() : Profile(), nNodes(0), radii(NULL), data(NULL), 00120 y2(NULL), pointIndices(NULL) {}; 00121 00126 double* spline(float* x, Data** y, int attributeIndex, 00127 double yp1, double ypn) const; 00128 00134 void check(int attributeIndex) const; 00135 00136 public: 00137 00150 ProfileNPoint(float* r, Data** dat, int size) : Profile(), nNodes(size), radii(NULL), 00151 data(NULL), y2(NULL), pointIndices(NULL) 00152 { 00153 radii = new float[size]; 00154 data = new Data*[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 ProfileNPoint(const vector<float>& r, vector<Data*>& d) 00186 : Profile(), nNodes(r.size()), radii(NULL), 00187 data(NULL), y2(NULL), pointIndices(NULL) 00188 { 00189 radii = new float[nNodes]; 00190 data = new Data*[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 ProfileNPoint(float* rad, const vector<Data*>& dat); 00226 00230 static string class_name() { return "ProfileNPoint"; }; 00231 00235 virtual int class_size() const 00236 { return (int) sizeof(ProfileNPoint); }; 00237 00243 virtual const ProfileType& getType() const 00244 { return ProfileType::NPOINT; }; 00245 00249 virtual bool operator == (const Profile& p) const 00250 { 00251 if (!Profile::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 Data** getData() 00306 { 00307 Data** da = new Data*[nNodes]; 00308 for (int i=0; i<nNodes; ++i) da[i] = data[i]; 00309 return da; 00310 } 00311 00312 00316 virtual Data* getData(int i) { return data[i]; }; 00317 00321 virtual const Data& getData(int i) const { return *(data[i]); }; 00322 00326 virtual void setData(const vector<Data*>& 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, Data* inData) 00338 { delete data[index]; data[index] = inData; } 00339 00343 virtual float getRadiusTop() const { return radii[nNodes - 1]; }; 00344 00348 virtual const Data& getDataTop() const { return *data[nNodes - 1]; }; 00349 00353 virtual Data* getDataTop() { return data[nNodes - 1]; }; 00354 00358 virtual float getRadiusBottom() const { return radii[0]; }; 00359 00363 virtual const Data& getDataBottom() const { return *data[0]; }; 00364 00368 virtual Data* 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 InterpolatorType& 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 ProfileNPoint(IFStreamBinary& ifs, GeoTessMetaData& gtmd); 00419 00423 ProfileNPoint(IFStreamAscii& ifs, GeoTessMetaData& gtmd); 00424 00428 virtual ~ProfileNPoint(); 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 = Profile::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 = Profile::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 = Profile::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 InterpolatorType& 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 Profile* copy() 00598 { 00599 Data** d = new Data* [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 ProfileNPoint(r, d, nNodes); 00607 } 00608 00610 00611 }; // end class ProfileNPoint 00612 00624 inline double ProfileNPoint::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 ProfileNPoint::getValue(const InterpolatorType& 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 ProfileNPoint::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