GeoTessCPP  2.0.0
Software to facilitate storage and retrieval of 3D information about the Earth.
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
ProfileNPoint.h
Go to the documentation of this file.
1 //- ****************************************************************************
2 //-
3 //- Copyright 2009 Sandia Corporation. Under the terms of Contract
4 //- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
5 //- retains certain rights in this software.
6 //-
7 //- BSD Open Source License.
8 //- All rights reserved.
9 //-
10 //- Redistribution and use in source and binary forms, with or without
11 //- modification, are permitted provided that the following conditions are met:
12 //-
13 //- * Redistributions of source code must retain the above copyright notice,
14 //- this list of conditions and the following disclaimer.
15 //- * Redistributions in binary form must reproduce the above copyright
16 //- notice, this list of conditions and the following disclaimer in the
17 //- documentation and/or other materials provided with the distribution.
18 //- * Neither the name of Sandia National Laboratories nor the names of its
19 //- contributors may be used to endorse or promote products derived from
20 //- this software without specific prior written permission.
21 //-
22 //- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 //- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 //- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 //- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 //- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 //- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 //- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 //- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 //- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 //- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //- POSSIBILITY OF SUCH DAMAGE.
33 //-
34 //- ****************************************************************************
35 
36 #ifndef PROFILENPOINT_OBJECT_H
37 #define PROFILENPOINT_OBJECT_H
38 
39 // **** _SYSTEM INCLUDES_ ******************************************************
40 
41 #include <iostream>
42 #include <string>
43 #include <fstream>
44 #include <sstream>
45 
46 // use standard library objects
47 using namespace std;
48 
49 // **** _LOCAL INCLUDES_ *******************************************************
50 
51 #include "GeoTessUtils.h"
52 #include "GeoTessException.h"
53 #include "Data.h"
54 #include "Profile.h"
55 #include "ProfileType.h"
56 #include "InterpolatorType.h"
57 
58 // **** _BEGIN GEOTESS NAMESPACE_ **********************************************
59 
60 namespace geotess {
61 
62 // **** _FORWARD REFERENCES_ ***************************************************
63 
64 class GeoTessMetaData;
65 class IFStreamAscii;
66 class IFStreamBinary;
67 
68 // **** _CLASS DEFINITION_ *****************************************************
69 
80 class GEOTESS_EXP_IMP ProfileNPoint : virtual public Profile
81 {
82 private:
83 
87  int nNodes;
88 
92  float* radii;
93 
97  Data** data;
98 
105  mutable double** y2;
106 
114  int* pointIndices;
115 
119  ProfileNPoint() : Profile(), nNodes(0), radii(NULL), data(NULL),
120  y2(NULL), pointIndices(NULL) {};
121 
126  double* spline(float* x, Data** y, int attributeIndex,
127  double yp1, double ypn) const;
128 
134  void check(int attributeIndex) const;
135 
136 public:
137 
150  ProfileNPoint(float* r, Data** dat, int size) : Profile(), nNodes(size), radii(NULL),
151  data(NULL), y2(NULL), pointIndices(NULL)
152  {
153  radii = new float[size];
154  data = new Data*[size];
155  for (int i=0; i<size; ++i)
156  {
157  radii[i] = r[i];
158  data[i] = dat[i];
159  }
160 
161  if (radii[0] > radii[size - 1])
162  {
163  ostringstream os;
164  os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
165  << "Profile has negative thickness" << endl;
166  os << "radii = ";
167  for (int i=0; i<size; ++i)
168  os << radii[i] << ", ";
169  os << endl;
170  throw GeoTessException(os, __FILE__, __LINE__, 4301);
171  }
172  }
173 
185  ProfileNPoint(const vector<float>& r, vector<Data*>& d)
186  : Profile(), nNodes(r.size()), radii(NULL),
187  data(NULL), y2(NULL), pointIndices(NULL)
188  {
189  radii = new float[nNodes];
190  data = new Data*[nNodes];
191  for (int i=0; i<nNodes; ++i)
192  {
193  radii[i] = r[i];
194  data[i] = d[i];
195  }
196 
197  if (r.size() != d.size())
198  {
199  ostringstream os;
200  os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
201  << "radii.size() != data.size()" << endl;
202  os << "radii.size = " << r.size() << endl;
203  os << "data.size = " << d.size() << endl;
204  throw GeoTessException(os, __FILE__, __LINE__, 4302);
205  }
206 
207  if (radii[0] > radii[nNodes - 1])
208  {
209  ostringstream os;
210  os << endl << "ERROR in ProfileNPoint::ProfileNPoint" << endl
211  << "Profile has negative thickness" << endl;
212  os << "radii = ";
213  for (int i=0; i<nNodes; ++i)
214  os << radii[i] << ", ";
215  os << endl;
216  throw GeoTessException(os, __FILE__, __LINE__, 4303);
217  }
218  }
219 
225  ProfileNPoint(float* rad, const vector<Data*>& dat);
226 
230  static string class_name() { return "ProfileNPoint"; };
231 
235  virtual int class_size() const
236  { return (int) sizeof(ProfileNPoint); };
237 
243  virtual const ProfileType& getType() const
244  { return ProfileType::NPOINT; };
245 
249  virtual bool operator == (const Profile& p) const
250  {
251  if (!Profile::operator==(p)) return false;
252 
253  if (nNodes != p.getNRadii()) return false;
254 
255  for (int i = 0; i < nNodes; ++i)
256  if ((radii[i] != p.getRadius(i)) ||
257  (!(*(data[i]) == p.getData(i))))
258  return false;
259 
260  return true;
261  }
262 
270  bool isNaN(int nodeIndex, int attributeIndex)
271  { return data[nodeIndex]->isNaN(attributeIndex); };
272 
277  virtual float getRadius(int i) const { return radii[i]; };
278 
283  virtual Data** getData() { return data; };
284 
288  virtual Data* getData(int i) { return data[i]; };
289 
293  virtual const Data& getData(int i) const { return *(data[i]); };
294 
298  virtual void setData(const vector<Data*>& inData);
299 
300  // TODO: added by sb 9/27/2012
304  virtual void setRadii(const vector<float>& newRadii)
305  { for (int i=0; i<nNodes; ++i) radii[i] = newRadii[i]; }
306 
307  // *** TODO added 7/19/2012
311  virtual void setData(int index, Data* inData)
312  { delete data[index]; data[index] = inData; }
313 
317  virtual float getRadiusTop() const { return radii[nNodes - 1]; };
318 
322  virtual const Data& getDataTop() const { return *data[nNodes - 1]; };
323 
327  virtual Data* getDataTop() { return data[nNodes - 1]; };
328 
332  virtual float getRadiusBottom() const { return radii[0]; };
333 
337  virtual const Data& getDataBottom() const { return *data[0]; };
338 
342  virtual Data* getDataBottom() { return data[0]; };
343 
347  virtual int getNRadii() const { return nNodes; };
348 
352  virtual int getNData() const { return nNodes; };
353 
357  virtual float* getRadii()
358  {
359  float* fa = new float [nNodes];
360  for (int i=0; i<nNodes; ++i) fa[i] = radii[i];
361  return fa;
362  }
363 
364 
365  // *** TODO added 7/20/2012
370  virtual double getValue(int attributeIndex, int radiusIndex) const
371  { return data[radiusIndex]->getDouble(attributeIndex); }
372 
379  virtual double getValueTop(int attributeIndex) const
380  { return data[nNodes-1]->getDouble(attributeIndex); }
381 
386  virtual double getInterpolationCoefficient(int index, double radius) const;
387 
388  // *** TODO modified interface 7/19/2012
393  virtual double getValue(const InterpolatorType& radialType,
394  int attributeIndex, double radius,
395  bool allowRadiusOutOfRange) const;
396 
401  virtual int getRadiusIndex(double radius, int jlo) const;
402 
403  // *** TODO added 7/20/2012
407  virtual double getInterpolationCoefficient(int index, double radius,
408  bool allowOutOfRange) const;
409 
411 
416 
421 
425  virtual ~ProfileNPoint();
426 
430  virtual void write(IFStreamBinary& ofs);
431 
435  virtual void write(IFStreamAscii& ofs);
436 
437  // *** TODO added 7/20/2012
446  virtual int findClosestRadiusIndex(double radius) const
447  {
448  int i = Profile::getRadiusIndex(radius);
449  return abs(radii[i+1] - radius) < abs(radii[i] - radius) ? i+1 : i;
450  }
451 
452  // *** TODO added 7/20/2012
460  virtual void setPointIndex(int nodeIndex, int pointIndex)
461  {
462  if (pointIndices == NULL)
463  {
464  if (pointIndex < 0) return;
465 
466  pointIndices = new int [nNodes];
467  for (int i = 0; i < nNodes; ++i) pointIndices[i] = -1;
468  }
469  pointIndices[nodeIndex] = pointIndex;
470  }
471 
472  // *** TODO added 10/14/2012
480  virtual void resetPointIndices()
481  {
482  if (pointIndices != NULL)
483  delete[] pointIndices;
484  pointIndices = NULL;
485  }
486 
487  // *** TODO added 7/20/2012
495  virtual int getPointIndex(int nodeIndex) const
496  { return pointIndices == NULL ? -1 : pointIndices[nodeIndex]; }
497 
498  // *** TODO added 7/20/2012
505  virtual void getWeights(map<int, double>& weights,
506  double dkm, double radius, double hcoefficient) const
507  {
508  int node = Profile::getRadiusIndex(radius);
509 
510  //TODO: need getInterpolationCoefficient to work for cubic spline interpolator. It currently does not.
511 
512  // get coefficient at node influencing position radius
513 
514  int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
515 
516  double c = getInterpolationCoefficient(node, radius, true);
517  if (c > 0.0)
518  {
519  map<int, double>::iterator it = weights.find(pointIndex);
520  if (it == weights.end())
521  weights[pointIndex] = dkm * hcoefficient * c;
522  else
523  it->second += dkm * hcoefficient * c;
524  }
525 
526  // now get coefficient at node+1 influencing position radius
527 
528  c = 1.0 - c;
529  pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
530  if (c > 0.0)
531  {
532  map<int, double>::iterator it = weights.find(pointIndex);
533  if (it == weights.end())
534  weights[pointIndex] = dkm * hcoefficient * c;
535  else
536  it->second += dkm * hcoefficient * c;
537  }
538  }
539 
540  // *** TODO added 7/26/2012
547  virtual void getCoefficients(map<int, double>& coefficients, double radius,
548  double horizontalCoefficient) const
549  {
550  int node = Profile::getRadiusIndex(radius);
551 
552  //TODO: need getInterpolationCoefficient to work for cubic spline interpolator. It currently does not.
553  double c = getInterpolationCoefficient(node, radius, true);
554 
555  int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
556 
557  if (c > 0.0)
558  coefficients[pointIndex] = c * horizontalCoefficient;
559 
560  pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
561 
562  if (c < 1.0)
563  coefficients[pointIndex] = (1.0 - c) * horizontalCoefficient;
564  }
565 
566  virtual void setInterpolationCoefficients(const InterpolatorType& interpType,
567  vector<int>& nodeIndexes, vector<double>& coefficients,
568  double& radius, bool& allowOutOfRange)
569  {
570  //TODO: need this method to work for cubic spline interpolator. It currently does not.
571 
572  if (radius < radii[0])
573  {
574  nodeIndexes.push_back(0);
575  coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
576  }
577  else if (radius > radii[nNodes-1])
578  {
579  nodeIndexes.push_back(nNodes-1);
580  coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
581  }
582  else
583  {
584  int index = getRadiusIndex(radius, -1);
585  double c = ((double)radii[index + 1] - radius) /
586  ((double)radii[index + 1] - (double)radii[index]);
587  nodeIndexes.push_back(index);
588  coefficients.push_back(c);
589  if (c < 1.)
590  {
591  nodeIndexes.push_back(index+1);
592  coefficients.push_back(1.-c);
593  }
594  }
595  }
596 
597  // *** TODO added 8/20/2012
601  virtual Profile* copy()
602  {
603  Data** d = new Data* [nNodes];
604  float* r = new float [nNodes];
605  for (int i = 0; i < nNodes; ++i)
606  {
607  d[i] = data[i]->copy();
608  r[i] = radii[i];
609  }
610  return new ProfileNPoint(r, d, nNodes);
611  }
612 
614 
615 }; // end class ProfileNPoint
616 
628 inline double ProfileNPoint::getInterpolationCoefficient(int index, double radius) const
629 {
630  if (radius <= radii[index]) return 1.0;
631  if (radius >= radii[index + 1]) return 0.0;
632  return (radii[index + 1] - radius) / (radii[index + 1] - radii[index]);
633 }
634 
647 inline double ProfileNPoint::getValue(const InterpolatorType& radialType,
648  int attributeIndex, double radius, bool allowRadiusOutOfRange) const
649 {
650  if (!allowRadiusOutOfRange &&
651  ((radius < (double)radii[0]) || (radius > (double)radii[nNodes-1])))
652  return NaN_DOUBLE;
653 
654  int index = getRadiusIndex(radius, -1);
655 
656  double r0 = radii[index];
657  double v0 = data[index]->getDouble(attributeIndex);
658 
659  if (radius <= r0) return v0;
660 
661  double r1 = radii[index + 1];
662  double v1 = data[index + 1]->getDouble(attributeIndex);
663 
664  if (radius >= r1) return v1;
665 
666  double a = (r1 - radius) / (r1 - r0);
667 
668  double b = 1. - a;
669  double v = a * v0 + b * v1;
670 
671  switch (radialType.ordinal())
672  {
673  case 0: // LINEAR
674  return v;
675 
676  case 2: // CUBIC_SPLINE
677  check(attributeIndex);
678  return v + ((a * a * a - a) * y2[attributeIndex][index]
679  + (b * b * b - b) * y2[attributeIndex][index + 1])
680  * (r1 - r0) * (r1 - r0) / 6.0;
681 
682  default:
683  ostringstream os;
684  os << endl << "ERROR in ProfileNPoint::getValue" << endl
685  << "InterpolatorType: " << radialType.name()
686  << " cannot be applied to a Profile." << endl
687  << "Must specify LINEAR or SPLINE" << endl;
688  throw GeoTessException(os, __FILE__, __LINE__, 4304);
689  }
690 }
691 
693 
699 inline void ProfileNPoint::check(int attributeIndex) const
700 {
701  if (y2 == NULL)
702  {
703  y2 = new double* [data[0]->size()];
704  for (int i=0; i<data[0]->size(); ++i)
705  y2[i] = NULL;
706  }
707  if (y2[attributeIndex] == NULL)
708  y2[attributeIndex] = spline(radii, data, attributeIndex, 1.0e30, 1.0e30);
709 }
710 
712 
713 } // end namespace geotess
714 
715 #endif // PROFILENPOINT_OBJECT_H