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
GeoTessProfileNPoint.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 "GeoTessData.h"
54 #include "GeoTessProfile.h"
55 #include "GeoTessProfileType.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 
81 {
82 private:
83 
87  int nNodes;
88 
92  float* radii;
93 
97  GeoTessData** data;
98 
105  mutable double** y2;
106 
114  int* pointIndices;
115 
119  GeoTessProfileNPoint() : GeoTessProfile(), nNodes(0), radii(NULL), data(NULL),
120  y2(NULL), pointIndices(NULL) {};
121 
126  double* spline(float* x, GeoTessData** y, int attributeIndex,
127  double yp1, double ypn) const;
128 
134  void check(int attributeIndex) const;
135 
136 public:
137 
150  GeoTessProfileNPoint(float* r, GeoTessData** dat, int size) : GeoTessProfile(), nNodes(size), radii(NULL),
151  data(NULL), y2(NULL), pointIndices(NULL)
152  {
153  radii = new float[size];
154  data = new GeoTessData*[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  GeoTessProfileNPoint(const vector<float>& r, vector<GeoTessData*>& d)
186  : GeoTessProfile(), nNodes(r.size()), radii(NULL),
187  data(NULL), y2(NULL), pointIndices(NULL)
188  {
189  radii = new float[nNodes];
190  data = new GeoTessData*[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  GeoTessProfileNPoint(float* rad, const vector<GeoTessData*>& dat);
226 
230  static string class_name() { return "ProfileNPoint"; };
231 
235  virtual int class_size() const
236  { return (int) sizeof(GeoTessProfileNPoint); };
237 
243  virtual const GeoTessProfileType& getType() const
244  { return GeoTessProfileType::NPOINT; };
245 
249  virtual bool operator == (const GeoTessProfile& p) const
250  {
251  if (!GeoTessProfile::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 
282  virtual int getNRadii() const { return nNodes; };
283 
287  virtual int getNData() const { return nNodes; };
288 
293  virtual float* getRadii()
294  {
295  float* fa = new float [nNodes];
296  for (int i=0; i<nNodes; ++i) fa[i] = radii[i];
297  return fa;
298  }
299 
305  virtual GeoTessData** getData()
306  {
307  GeoTessData** da = new GeoTessData*[nNodes];
308  for (int i=0; i<nNodes; ++i) da[i] = data[i];
309  return da;
310  }
311 
312 
316  virtual GeoTessData* getData(int i) { return data[i]; };
317 
321  virtual const GeoTessData& getData(int i) const { return *(data[i]); };
322 
326  virtual void setData(const vector<GeoTessData*>& inData);
327 
331  virtual void setRadii(const vector<float>& newRadii)
332  { for (int i=0; i<nNodes; ++i) radii[i] = newRadii[i]; }
333 
337  virtual void setData(int index, GeoTessData* inData)
338  { delete data[index]; data[index] = inData; }
339 
343  virtual float getRadiusTop() const { return radii[nNodes - 1]; };
344 
348  virtual const GeoTessData& getDataTop() const { return *data[nNodes - 1]; };
349 
353  virtual GeoTessData* getDataTop() { return data[nNodes - 1]; };
354 
358  virtual float getRadiusBottom() const { return radii[0]; };
359 
363  virtual const GeoTessData& getDataBottom() const { return *data[0]; };
364 
368  virtual GeoTessData* getDataBottom() { return data[0]; };
369 
370 
375  virtual double getValue(int attributeIndex, int radiusIndex) const
376  { return data[radiusIndex]->getDouble(attributeIndex); }
377 
384  virtual double getValueTop(int attributeIndex) const
385  { return data[nNodes-1]->getDouble(attributeIndex); }
386 
391  virtual double getInterpolationCoefficient(int index, double radius) const;
392 
397  virtual double getValue(const GeoTessInterpolatorType& radialType,
398  int attributeIndex, double radius,
399  bool allowRadiusOutOfRange) const;
400 
405  virtual int getRadiusIndex(double radius, int jlo) const;
406 
410  virtual double getInterpolationCoefficient(int index, double radius,
411  bool allowOutOfRange) const;
412 
414 
419 
424 
428  virtual ~GeoTessProfileNPoint();
429 
433  virtual void write(IFStreamBinary& ofs);
434 
438  virtual void write(IFStreamAscii& ofs);
439 
448  virtual int findClosestRadiusIndex(double radius) const
449  {
450  int i = GeoTessProfile::getRadiusIndex(radius);
451  return abs(radii[i+1] - radius) < abs(radii[i] - radius) ? i+1 : i;
452  }
453 
461  virtual void setPointIndex(int nodeIndex, int pointIndex)
462  {
463  if (pointIndices == NULL)
464  {
465  if (pointIndex < 0) return;
466 
467  pointIndices = new int [nNodes];
468  for (int i = 0; i < nNodes; ++i) pointIndices[i] = -1;
469  }
470  pointIndices[nodeIndex] = pointIndex;
471  }
472 
480  virtual void resetPointIndices()
481  {
482  if (pointIndices != NULL)
483  delete[] pointIndices;
484  pointIndices = NULL;
485  }
486 
494  virtual int getPointIndex(int nodeIndex) const
495  { return pointIndices == NULL ? -1 : pointIndices[nodeIndex]; }
496 
503  virtual void getWeights(map<int, double>& weights,
504  double dkm, double radius, double hcoefficient) const
505  {
506  int node = GeoTessProfile::getRadiusIndex(radius);
507 
508  //TODO: need getInterpolationCoefficient to work for cubic spline interpolator. It currently does not.
509 
510  // get coefficient at node influencing position radius
511 
512  int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
513 
514  double c = getInterpolationCoefficient(node, radius, true);
515  if (c > 0.0)
516  {
517  map<int, double>::iterator it = weights.find(pointIndex);
518  if (it == weights.end())
519  weights[pointIndex] = dkm * hcoefficient * c;
520  else
521  it->second += dkm * hcoefficient * c;
522  }
523 
524  // now get coefficient at node+1 influencing position radius
525 
526  c = 1.0 - c;
527  pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
528  if (c > 0.0)
529  {
530  map<int, double>::iterator it = weights.find(pointIndex);
531  if (it == weights.end())
532  weights[pointIndex] = dkm * hcoefficient * c;
533  else
534  it->second += dkm * hcoefficient * c;
535  }
536  }
537 
544  virtual void getCoefficients(map<int, double>& coefficients, double radius,
545  double horizontalCoefficient) const
546  {
547  int node = GeoTessProfile::getRadiusIndex(radius);
548 
549  //TODO: need getInterpolationCoefficient to work for cubic spline interpolator. It currently does not.
550  double c = getInterpolationCoefficient(node, radius, true);
551 
552  int pointIndex = pointIndices == NULL ? -1 : pointIndices[node];
553 
554  if (c > 0.0)
555  coefficients[pointIndex] = c * horizontalCoefficient;
556 
557  pointIndex = pointIndices == NULL ? -1 : pointIndices[node+1];
558 
559  if (c < 1.0)
560  coefficients[pointIndex] = (1.0 - c) * horizontalCoefficient;
561  }
562 
563  virtual void setInterpolationCoefficients(const GeoTessInterpolatorType& interpType,
564  vector<int>& nodeIndexes, vector<double>& coefficients,
565  double& radius, bool& allowOutOfRange)
566  {
567  //TODO: need this method to work for cubic spline interpolator. It currently does not.
568 
569  if (radius < radii[0])
570  {
571  nodeIndexes.push_back(0);
572  coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
573  }
574  else if (radius > radii[nNodes-1])
575  {
576  nodeIndexes.push_back(nNodes-1);
577  coefficients.push_back(allowOutOfRange ? 1 : NaN_DOUBLE);
578  }
579  else
580  {
581  int index = getRadiusIndex(radius, -1);
582  double c = ((double)radii[index + 1] - radius) /
583  ((double)radii[index + 1] - (double)radii[index]);
584  nodeIndexes.push_back(index);
585  coefficients.push_back(c);
586  if (c < 1.)
587  {
588  nodeIndexes.push_back(index+1);
589  coefficients.push_back(1.-c);
590  }
591  }
592  }
593 
597  virtual GeoTessProfile* copy()
598  {
599  GeoTessData** d = new GeoTessData* [nNodes];
600  float* r = new float [nNodes];
601  for (int i = 0; i < nNodes; ++i)
602  {
603  d[i] = data[i]->copy();
604  r[i] = radii[i];
605  }
606  return new GeoTessProfileNPoint(r, d, nNodes);
607  }
608 
610 
611 }; // end class ProfileNPoint
612 
624 inline double GeoTessProfileNPoint::getInterpolationCoefficient(int index, double radius) const
625 {
626  if (radius <= radii[index]) return 1.0;
627  if (radius >= radii[index + 1]) return 0.0;
628  return (radii[index + 1] - radius) / (radii[index + 1] - radii[index]);
629 }
630 
643 inline double GeoTessProfileNPoint::getValue(const GeoTessInterpolatorType& radialType,
644  int attributeIndex, double radius, bool allowRadiusOutOfRange) const
645 {
646  if (!allowRadiusOutOfRange &&
647  ((radius < (double)radii[0]) || (radius > (double)radii[nNodes-1])))
648  return NaN_DOUBLE;
649 
650  int index = getRadiusIndex(radius, -1);
651 
652  double r0 = radii[index];
653  double v0 = data[index]->getDouble(attributeIndex);
654 
655  if (radius <= r0) return v0;
656 
657  double r1 = radii[index + 1];
658  double v1 = data[index + 1]->getDouble(attributeIndex);
659 
660  if (radius >= r1) return v1;
661 
662  double a = (r1 - radius) / (r1 - r0);
663 
664  double b = 1. - a;
665  double v = a * v0 + b * v1;
666 
667  switch (radialType.ordinal())
668  {
669  case 0: // LINEAR
670  return v;
671 
672  case 2: // CUBIC_SPLINE
673  check(attributeIndex);
674  return v + ((a * a * a - a) * y2[attributeIndex][index]
675  + (b * b * b - b) * y2[attributeIndex][index + 1])
676  * (r1 - r0) * (r1 - r0) / 6.0;
677 
678  default:
679  ostringstream os;
680  os << endl << "ERROR in ProfileNPoint::getValue" << endl
681  << "InterpolatorType: " << radialType.name()
682  << " cannot be applied to a Profile." << endl
683  << "Must specify LINEAR or SPLINE" << endl;
684  throw GeoTessException(os, __FILE__, __LINE__, 4304);
685  }
686 }
687 
689 
695 inline void GeoTessProfileNPoint::check(int attributeIndex) const
696 {
697  if (y2 == NULL)
698  {
699  y2 = new double* [data[0]->size()];
700  for (int i=0; i<data[0]->size(); ++i)
701  y2[i] = NULL;
702  }
703  if (y2[attributeIndex] == NULL)
704  y2[attributeIndex] = spline(radii, data, attributeIndex, 1.0e30, 1.0e30);
705 }
706 
708 
709 } // end namespace geotess
710 
711 #endif // PROFILENPOINT_OBJECT_H