19 #pragma warning(disable : 4512) // boost code: no assignment operator    20 #include <boost/geometry.hpp>    21 #include <boost/geometry/index/rtree.hpp>    22 #include <boost/unordered_map.hpp>    29 #include <xmsgrid/geometry/geoms.h>    30 #include <xmsgrid/geometry/GmTriSearch.h>    62                      const std::vector<int>& a_tris,
    63                      const std::vector<float>& a_scalar,
    64                      GmTriSearch* a_triSearch);
    66   virtual float InterpToPt(
const xms::Pt3d& a_pt) 
override;
    67   virtual void GetNeighbors(
int a_ptIdx, std::vector<int>& a_neigh) 
override;
    71   virtual std::string 
ToString() 
override;
    76   void EdgesFromTri(
int a_triIdx, std::pair<int, int> a_edges[3]);
    84                             const xms::Pt3d& a_pt,
    85                             std::vector<nnOuterEdgeStruct>& a_outerEdges,
    86                             std::map<int, double>& a_weights);
    93                           const xms::Pt3d& a_pt);
    96                                  std::map<int, double>& a_weights);
    99   double ScalarFromWeights(std::map<int, double>& a_weights, 
const xms::Pt3d& a_pt);
   103   typedef boost::unordered_map<std::pair<int, int>, std::pair<int, int>> 
MapEdges;
   105   const std::vector<xms::Pt3d>& 
m_pts; 
   121 static std::pair<int, int> iMakePair(
int a_first, 
int a_second)
   123   if (a_first < a_second)
   124     return std::make_pair(a_first, a_second);
   125   return std::make_pair(a_second, a_first);
   137                                          const std::vector<int>& a_tris,
   138                                          const std::vector<float>& a_scalar,
   139                                          GmTriSearch* a_triSearch)
   141   BSHP<InterpNatNeighImpl> r(
new InterpNatNeighImpl(a_pts, a_tris, a_scalar, a_triSearch));
   169                                        const std::vector<int>& a_tris,
   170                                        const std::vector<float>& a_scalar,
   171                                        GmTriSearch* a_triSearch)
   178 , m_triSearch(a_triSearch)
   179 , m_blendWeights(false)
   201   const xms::Pt3d& p(
m_pts[a_ptIdx]);
   203   std::vector<int> tris;
   206   std::set<int> ptIdxs;
   208   for (
size_t i = 0; i < tris.size(); ++i)
   210     for (
int j = 0; j < 3; ++j)
   211       ptIdxs.insert(
m_tris[tris[i] + j]);
   213   ptIdxs.erase(a_ptIdx);
   214   a_neigh.assign(ptIdxs.begin(), ptIdxs.end());
   230     m_nf->ComputeNodalFuncs();
   246   std::stringstream ss;
   250   ss << 
m_tol << 
"=tol ";
   252   for (MapEdges::iterator it = 
m_edges.begin(); it != 
m_edges.end(); ++it)
   254     ss << it->first.first << 
" " << it->first.second << 
" " << it->second.first << 
" "   255        << it->second.second << 
" ";
   270   std::pair<int, int> pr;
   272   for (
size_t i = 0; i < 
m_tris.size(); i += 3)
   275     std::pair<int, int> tp[3];
   277     for (
int j = 0; j < 3; ++j)
   300   xms::Pt3d pt, ptMin, ptMax;
   301   ptMin = ptMax = 
m_pts[0];
   302   for (
size_t i = 1; i < 
m_pts.size(); ++i)
   309   m_tol = gmXyDistance(ptMin, ptMax) / 1e9;
   311   for (
size_t i = 0, cnt = 0; i < 
m_tris.size(); i += 3, ++cnt)
   316     gmCircumcircleWithTol(&p0, &p1, &p2, &pt.x, &pt.y, &pt.z, 
m_tol);
   327   a_edges[0] = iMakePair(
m_tris[a_triIdx], 
m_tris[a_triIdx + 1]);
   328   a_edges[1] = iMakePair(
m_tris[a_triIdx + 1], 
m_tris[a_triIdx + 2]);
   329   a_edges[2] = iMakePair(
m_tris[a_triIdx + 2], 
m_tris[a_triIdx]);
   339   std::pair<int, int> edges[3];
   341   std::set<int> setTris;
   342   for (
int i = 0; i < 3; ++i)
   344     const std::pair<int, int>& pTri = 
m_edges[edges[i]];
   345     setTris.insert(pTri.first);
   347       setTris.insert(pTri.second);
   349   setTris.erase(a_triIdx);
   350   a_tris.assign(setTris.begin(), setTris.end());
   369   a_tris.push_back(tIdx);
   370   std::vector<int> visited(
m_tris.size(), 0);
   372   for (
size_t j = 0; j < a_tris.size(); ++j)
   375     std::vector<int> vals;
   378     double rSquared, distSquared;
   379     std::set<int> ptIdxs;
   381     for (
size_t i = 0; i < vals.size(); ++i)
   383       size_t tri = vals[i];
   387       distSquared = gmXyDistanceSquared(
m_centers[tri / 3], a_pt);
   389       if (distSquared <= rSquared)
   390         a_tris.push_back((
int)tri);
   401   return ((-2.0 * x * x * x) + (3.0 * x * x));
   411   double rval((
double)
m_scalar[a_ptIdx]);
   414     rval = 
m_nf->ScalarFromPtIdx(a_ptIdx, a_loc);
   436   std::map<int, double> weights;
   437   std::vector<nnOuterEdgeStruct> outerEdges;
   460                                               const xms::Pt3d& a_pt,
   461                                               std::vector<nnOuterEdgeStruct>& a_outerEdges,
   462                                               std::map<int, double>& a_weights)
   464   std::set<std::pair<int, int>> processedEdges;
   465   std::vector<int> tris(1, a_tIdx);
   466   for (
size_t t = 0; t < tris.size(); ++t)
   468     std::pair<int, int> edge;
   470     for (
int i = 0; i < 3; ++i)
   472       int ptIdx = 
m_tris[tIdx + i];
   473       int nextTriPtIdx = i == 2 ? 0 : i + 1;
   474       int ptIdx1 = 
m_tris[tIdx + nextTriPtIdx];
   475       edge = iMakePair(ptIdx, ptIdx1);
   477       if (processedEdges.find(edge) != processedEdges.end())
   491       double cross = (tCC.x * adjCC.y) - (tCC.y * adjCC.x);
   492       a_weights[ptIdx] -= cross;
   493       a_weights[ptIdx1] += cross;
   495       tris.push_back(adjTri);
   497       processedEdges.insert(edge);
   511   boost::unordered_map<std::pair<int, int>, std::pair<int, int>>::iterator it(
m_edges.find(a_edge));
   514     rval = it->second.first;
   515     if (a_triIdx == rval)
   516       rval = it->second.second;
   528   const xms::Pt3d& cc = 
m_centers[a_tri / 3];
   529   double d2 = gmXyDistanceSquared(a_pt, cc);
   546                                             const xms::Pt3d& a_pt)
   562   std::vector<nnOuterEdgeStruct> e(a_);
   563   for (
size_t i = 1; i < a_.size(); ++i)
   565     for (
size_t j = 1; j < e.size(); ++j)
   567       if (e[j].m_edge[0] == a_[i - 1].m_edge[1])
   578                                                    std::map<int, double>& a_weights)
   580   for (
size_t i = 0; i < a_outerEdges.size(); ++i)
   583     size_t nextIdx = i + 1 == a_outerEdges.size() ? 0 : i + 1;
   586     int ptIdx = curr.
m_edge[1];
   591       double cross = (o1.x * c1.y) - (o1.y * c1.x);
   592       a_weights[ptIdx] += cross;
   593       a_weights[curr.
m_edge[0]] -= cross;
   599       xms::Pt3d &o1(curr.
m_cc), &c1(next.
m_cc);
   600       double cross = (o1.x * c1.y) - (o1.y * c1.x);
   601       a_weights[ptIdx] += cross;
   612   std::map<int, double>::iterator it(a_weights.begin());
   613   for (; it != a_weights.end(); ++it)
   615   for (it = a_weights.begin(); it != a_weights.end(); ++it)
   625   std::map<int, double>::iterator it(a_weights.begin());
   626   for (; it != a_weights.end(); ++it)
   631   for (it = a_weights.begin(); it != a_weights.end(); ++it)
   641                                              const xms::Pt3d& a_pt)
   644   std::map<int, double>::iterator it(a_weights.begin());
   645   for (; it != a_weights.end(); ++it)
   663 static void iGetPtsTris(std::vector<xms::Pt3d>& a_pts,
   664                         std::vector<int>& a_tris,
   665                         std::vector<float>& a_scalar)
   667   a_pts = {{26, 74, 5},  {15, 31, 8},  {60, -3, 4}, {78, 78, 7},
   668            {56, 64, 10}, {75, 45, 11}, {43, 22, 2}};
   669   a_tris = {0, 4, 3, 0, 1, 4, 4, 5, 3, 4, 6, 5, 4, 1, 6, 1, 2, 6, 2, 5, 6};
   670   a_scalar = {5.0f, 8.0f, 4.0f, 7.0f, 10.0f, 11.0f, 2.0f};
   685   std::vector<xms::Pt3d> pts;
   686   std::vector<int> tris;
   687   std::vector<float> scalar;
   695   xms::Pt3d loc(46, 27, 0);
   696   BSHP<std::vector<xms::Pt3d>> pts(
new std::vector<xms::Pt3d>());
   697   BSHP<std::vector<int>> tris(
new std::vector<int>());
   698   std::vector<int> tIdxs;
   699   std::vector<float> scalar;
   700   iGetPtsTris(*pts, *tris, scalar);
   701   BSHP<GmTriSearch> ts = GmTriSearch::New();
   702   ts->TrisToSearch(pts, tris);
   705   std::vector<int> nBase = {9, 12, 18, 3};
   713   BSHP<std::vector<xms::Pt3d>> pts(
new std::vector<xms::Pt3d>());
   714   BSHP<std::vector<int>> tris(
new std::vector<int>());
   715   std::vector<int> tIdxs;
   716   std::vector<float> scalar;
   717   iGetPtsTris(*pts, *tris, scalar);
   718   BSHP<GmTriSearch> ts = GmTriSearch::New();
   719   ts->TrisToSearch(pts, tris);
   722   std::vector<int> nBase = {1, 2, 4, 5};
   730   std::vector<nnOuterEdgeStruct> edges(5);
   731   edges[0].m_edge[0] = 5;
   732   edges[0].m_edge[1] = 1;
   733   edges[1].m_edge[0] = 3;
   734   edges[1].m_edge[1] = 4;
   735   edges[2].m_edge[0] = 2;
   736   edges[2].m_edge[1] = 3;
   737   edges[3].m_edge[0] = 4;
   738   edges[3].m_edge[1] = 5;
   739   edges[4].m_edge[0] = 1;
   740   edges[4].m_edge[1] = 2;
   741   BSHP<std::vector<xms::Pt3d>> pts(
new std::vector<xms::Pt3d>());
   742   BSHP<std::vector<int>> tris(
new std::vector<int>());
   743   std::vector<int> tIdxs;
   744   std::vector<float> scalar;
   745   iGetPtsTris(*pts, *tris, scalar);
   746   BSHP<GmTriSearch> ts = GmTriSearch::New();
   747   ts->TrisToSearch(pts, tris);
   750   int base[5][2] = {{5, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}};
   751   for (
size_t i = 0; i < edges.size(); ++i)
   753     TS_ASSERT_EQUALS(base[i][0], edges[i].m_edge[0]);
   761   BSHP<std::vector<xms::Pt3d>> pts(
new std::vector<xms::Pt3d>());
   762   BSHP<std::vector<int>> tris(
new std::vector<int>());
   763   std::vector<int> tIdxs;
   764   std::vector<float> scalar;
   765   iGetPtsTris(*pts, *tris, scalar);
   766   BSHP<GmTriSearch> ts = GmTriSearch::New();
   767   ts->TrisToSearch(pts, tris);
   769   std::vector<xms::Pt3d> iPts = {
   770     {36, 42, 0}, {39, 17, 0}, {64, 27, 0}, {55, 41, 0},
   771     {72, 64, 0}, {52, 73, 0}, {33, 60, 0}, {65.9404706, 54.0595293, 0}};
   773   std::vector<double> iVals(iPts.size(), 0);
   774   for (
size_t i = 0; i < iPts.size(); ++i)
   776   std::vector<double> nBase = {6.0669168950546712, 4.6727605118829985, 7.1629642928188586,
   777                                6.9812628044431957, 8.9941520467836238, 6.9374999999999991,
   778                                6.6593131032057444, 10.058329876949339};
 double HaleNnInterp(const xms::Pt3d &a_pt)
Implementation of natural neighbor interpolation taken from this paper A stable and fast implementati...
InterpNatNeighImpl(const std::vector< xms::Pt3d > &a_pts, const std::vector< int > &a_tris, const std::vector< float > &a_scalar, GmTriSearch *a_triSearch)
Consructor. 
bool PtInTriCircumCircle(const xms::Pt3d &a_pt, int a_tri)
Determines if a point is inside of a triangle circumcircle. 
int AdjacentTriangle(std::pair< int, int > &a_edge, int a_triIdx)
Gets the triangle adjacent to a_edge. 
std::vector< xms::Pt3d > m_centers
circumcircle centers of triangles 
xms::Pt3d m_cc
circumcenter of triangle made by interp pt with edge 
virtual void SetBlendWeights(bool a_) override
Turns on a flag for using a blending function when calculating weights. 
virtual ~InterpNatNeigh()
Destructor. 
convenience struct for natural neighbor interpolation 
const std::vector< xms::Pt3d > & m_pts
points interpolating from 
int m_triIdx
index of this triangle 
void FillEdgeMap()
Creates a map of edges for natural neighbor calculations. 
boost::unordered_map< std::pair< int, int >, std::pair< int, int > > MapEdges
typedef for long template 
InterpNatNeigh()
Constructor. 
void testCreateClass()
testing class creation 
Performs natural neighbor interpolation to a location. 
double ScalarFromWeights(std::map< int, double > &a_weights, const xms::Pt3d &a_pt)
Computes a scalar at a_pt based on the interpolation weights. 
void testGetTris()
testing getting the natural neighbor triangles 
void VecToStream(std::stringstream &a_ss, const T &a_v, std::string a_label)
void HaleNnOuterEdgesToWeights(std::vector< nnOuterEdgeStruct > &a_outerEdges, std::map< int, double > &a_weights)
Calculates weights from the outer edges. 
const std::vector< int > & m_tris
triangles interpolating from 
static boost::shared_ptr< InterpNatNeigh > New(const std::vector< Pt3d > &a_pts, const std::vector< int > &a_tris, const std::vector< float > &a_scalar, GmTriSearch *a_triSearch)
Creates a Natural Neighbor Interpolation class. 
double m_tol
tolerance for geometric floating point comparisons 
void HaleNnVisitNeighbors(int a_tIdx, const xms::Pt3d &a_pt, std::vector< nnOuterEdgeStruct > &a_outerEdges, std::map< int, double > &a_weights)
Visit the neighbors to a_pt and calculate the interpolation weight for the natural neighbors...
BSHP< NodalFunc > m_nf
Nodal function (constant, gradient plane, quadratic) 
void FillCenterVec()
calculate the circumcircle centers for all triangles 
void HaleNnSortOuterEdges(std::vector< nnOuterEdgeStruct > &a_)
Sorts the outer edges. 
virtual void GetNeighbors(int a_ptIdx, std::vector< int > &a_neigh) override
Finds neighboring triangles for the pt at a_ptIdx index in m_pts. 
virtual std::string ToString() override
serializes the class to a string 
virtual void SetNodalFunc(BSHP< NodalFunc > a_) override
Set the precomputed nodal function. 
void NormalizeWeights(std::map< int, double > &a_weights)
Normalizes the weights so that they sum to 1.0. 
virtual float InterpToPt(const xms::Pt3d &a_pt) override
Interpolates to a_pt. 
void NeighTriFromTriIdx(int a_triIdx, std::vector< int > &a_tris)
Gets the adjacent triangles to a_triIdx. 
virtual void RecalcNodalFunc() override
Recalculates the nodal function. This happens when the scalars change. 
void testHaleNnInterp()
testing the Hale NN interpolation 
void BlendWeights(std::map< int, double > &a_weights)
Blends the weights using BlendFunc. Smooths the interpolation. 
int m_edge[2]
pts that make up edge in CC order 
void testHaleNnSortOuterEdges()
testing sorting outer edges for the Hale NN method 
void testGetNeighbors()
testing getting the natural neighbor triangles 
void HaleNnAddOuterEdge(std::vector< nnOuterEdgeStruct > &a_, int a_tIdx, int a_ptIdx0, int a_ptIdx1, const xms::Pt3d &a_pt)
Adds a nnOuterEdgeStruct to a vector. 
GmTriSearch * m_triSearch
Spatial index for searching triangles. 
const std::vector< float > & m_scalar
scalar interpolating from 
double BlendFunc(double a_x)
Blending function to smooth interpolation weights refactored from GMS. 
bool m_blendWeights
flag for blending interpolation weights 
Class that performs natural neighbor interpolation. 
void GetNatNeighTriangles(const xms::Pt3d &a_pt, std::vector< int > &a_tris)
Given a pt this will find the "natural neighbor" triangles. First, we find the triangle that the pt i...
double ScalarFromNodalFunc(int a_ptIdx, const xms::Pt3d &a_loc)
calculates the scalar using the nodal function 
MapEdges m_edges
map of triangle edges 
void EdgesFromTri(int a_triIdx, std::pair< int, int > a_edges[3])
fill an array of edges from a triangle index