xmsinterp  1.0
InterpNatNeigh.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
6 //------------------------------------------------------------------------------
7 
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My header
14 
15 // 3. Standard Library Headers
16 
17 // 4. External Library Headers
18 #pragma warning(push)
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>
23 #pragma warning(pop)
24 
25 // 5. Shared Headers
26 #include <xmscore/math/math.h>
27 #include <xmscore/misc/XmError.h>
28 #include <xmscore/stl/utility.h>
29 #include <xmsgrid/geometry/geoms.h>
30 #include <xmsgrid/geometry/GmTriSearch.h>
32 #include <xmscore/misc/xmstype.h>
33 
34 // 6. Non-shared Headers
35 
36 //----- Forward declarations ---------------------------------------------------
37 
38 //----- External globals -------------------------------------------------------
39 
40 //----- Namespace declaration --------------------------------------------------
41 namespace xms
42 {
43 //----- Constants / Enumerations -----------------------------------------------
44 
45 //----- Classes / Structs ------------------------------------------------------
48 {
49 public:
51  int m_triIdx;
52  int m_edge[2];
53  xms::Pt3d m_cc;
54 };
55 //----- Internal functions -----------------------------------------------------
56 
57 //----- Class / Function definitions -------------------------------------------
59 {
60 public:
61  InterpNatNeighImpl(const std::vector<xms::Pt3d>& a_pts,
62  const std::vector<int>& a_tris,
63  const std::vector<float>& a_scalar,
64  GmTriSearch* a_triSearch);
65 
66  virtual float InterpToPt(const xms::Pt3d& a_pt) override;
67  virtual void GetNeighbors(int a_ptIdx, std::vector<int>& a_neigh) override;
68  virtual void SetNodalFunc(BSHP<NodalFunc> a_) override;
69  virtual void RecalcNodalFunc() override;
70  virtual void SetBlendWeights(bool a_) override;
71  virtual std::string ToString() override;
72 
73  //
74  void FillEdgeMap();
75  void FillCenterVec();
76  void EdgesFromTri(int a_triIdx, std::pair<int, int> a_edges[3]);
77  void NeighTriFromTriIdx(int a_triIdx, std::vector<int>& a_tris);
78  void GetNatNeighTriangles(const xms::Pt3d& a_pt, std::vector<int>& a_tris);
79  double BlendFunc(double a_x);
80  double ScalarFromNodalFunc(int a_ptIdx, const xms::Pt3d& a_loc);
81 
82  double HaleNnInterp(const xms::Pt3d& a_pt);
83  void HaleNnVisitNeighbors(int a_tIdx,
84  const xms::Pt3d& a_pt,
85  std::vector<nnOuterEdgeStruct>& a_outerEdges,
86  std::map<int, double>& a_weights);
87  int AdjacentTriangle(std::pair<int, int>& a_edge, int a_triIdx);
88  bool PtInTriCircumCircle(const xms::Pt3d& a_pt, int a_tri);
89  void HaleNnAddOuterEdge(std::vector<nnOuterEdgeStruct>& a_,
90  int a_tIdx,
91  int a_ptIdx0,
92  int a_ptIdx1,
93  const xms::Pt3d& a_pt);
94  void HaleNnSortOuterEdges(std::vector<nnOuterEdgeStruct>& a_);
95  void HaleNnOuterEdgesToWeights(std::vector<nnOuterEdgeStruct>& a_outerEdges,
96  std::map<int, double>& a_weights);
97  void NormalizeWeights(std::map<int, double>& a_weights);
98  void BlendWeights(std::map<int, double>& a_weights);
99  double ScalarFromWeights(std::map<int, double>& a_weights, const xms::Pt3d& a_pt);
100 
101 private:
103  typedef boost::unordered_map<std::pair<int, int>, std::pair<int, int>> MapEdges;
104 
105  const std::vector<xms::Pt3d>& m_pts;
106  const std::vector<int>& m_tris;
107  const std::vector<float>& m_scalar;
108  double m_tol;
110  std::vector<xms::Pt3d> m_centers;
111  BSHP<NodalFunc> m_nf;
112  GmTriSearch* m_triSearch;
114 };
115 
116 namespace
117 {
118 //------------------------------------------------------------------------------
120 //------------------------------------------------------------------------------
121 static std::pair<int, int> iMakePair(int a_first, int a_second)
122 {
123  if (a_first < a_second)
124  return std::make_pair(a_first, a_second);
125  return std::make_pair(a_second, a_first);
126 } // iMakePair
127 } // unnamed namespace
128 //------------------------------------------------------------------------------
135 //------------------------------------------------------------------------------
136 BSHP<InterpNatNeigh> InterpNatNeigh::New(const std::vector<xms::Pt3d>& a_pts,
137  const std::vector<int>& a_tris,
138  const std::vector<float>& a_scalar,
139  GmTriSearch* a_triSearch)
140 {
141  BSHP<InterpNatNeighImpl> r(new InterpNatNeighImpl(a_pts, a_tris, a_scalar, a_triSearch));
142  return r;
143 } // InterpNatNeigh::InterpNatNeigh
144 //------------------------------------------------------------------------------
146 //------------------------------------------------------------------------------
148 {
149 } // InterpNatNeigh::InterpNatNeigh
150 //------------------------------------------------------------------------------
152 //------------------------------------------------------------------------------
154 {
155 } // InterpNatNeigh::~InterpNatNeigh
156 
161 //------------------------------------------------------------------------------
167 //------------------------------------------------------------------------------
168 InterpNatNeighImpl::InterpNatNeighImpl(const std::vector<xms::Pt3d>& a_pts,
169  const std::vector<int>& a_tris,
170  const std::vector<float>& a_scalar,
171  GmTriSearch* a_triSearch)
172 : m_pts(a_pts)
173 , m_tris(a_tris)
174 , m_scalar(a_scalar)
175 , m_tol(1e-9)
176 , m_centers()
177 , m_nf()
178 , m_triSearch(a_triSearch)
179 , m_blendWeights(false)
180 {
181  FillEdgeMap();
182  FillCenterVec();
183 } // InterpNatNeighImpl::~InterpNatNeighImpl
184 //------------------------------------------------------------------------------
188 //------------------------------------------------------------------------------
189 float InterpNatNeighImpl::InterpToPt(const xms::Pt3d& a_pt)
190 {
191  return (float)(HaleNnInterp(a_pt));
192 } // InterpNatNeighImpl::InterpToPt
193 //------------------------------------------------------------------------------
198 //------------------------------------------------------------------------------
199 void InterpNatNeighImpl::GetNeighbors(int a_ptIdx, std::vector<int>& a_neigh)
200 {
201  const xms::Pt3d& p(m_pts[a_ptIdx]);
202  a_neigh.resize(0);
203  std::vector<int> tris;
204  GetNatNeighTriangles(p, tris);
205 
206  std::set<int> ptIdxs;
207  // now check to see if the point is inside the cirumcircle
208  for (size_t i = 0; i < tris.size(); ++i)
209  {
210  for (int j = 0; j < 3; ++j)
211  ptIdxs.insert(m_tris[tris[i] + j]);
212  }
213  ptIdxs.erase(a_ptIdx);
214  a_neigh.assign(ptIdxs.begin(), ptIdxs.end());
215 } // InterpNatNeighImpl::GetNeighbors
216 //------------------------------------------------------------------------------
219 //------------------------------------------------------------------------------
220 void InterpNatNeighImpl::SetNodalFunc(BSHP<NodalFunc> a_)
221 {
222  m_nf = a_;
223 } // InterpNatNeighImpl::SetNodalFunc
224 //------------------------------------------------------------------------------
226 //------------------------------------------------------------------------------
228 {
229  if (m_nf)
230  m_nf->ComputeNodalFuncs();
231 } // InterpNatNeighImpl::RecalcNodalFunc
232 //------------------------------------------------------------------------------
235 //------------------------------------------------------------------------------
237 {
238  m_blendWeights = a_;
239 } // InterpNatNeighImpl::SetBlendWeights
240 //------------------------------------------------------------------------------
243 //------------------------------------------------------------------------------
245 {
246  std::stringstream ss;
247  VecToStream(ss, m_pts, "pts");
248  VecToStream(ss, m_tris, "tris");
249  VecToStream(ss, m_scalar, "scalar");
250  ss << m_tol << "=tol ";
251  // typedef boost::unordered_map<std::pair<int, int>, std::pair<int, int>> MapEdges;
252  for (MapEdges::iterator it = m_edges.begin(); it != m_edges.end(); ++it)
253  {
254  ss << it->first.first << " " << it->first.second << " " << it->second.first << " "
255  << it->second.second << " ";
256  }
257  ss << "=edges ";
258  VecToStream(ss, m_centers, "centers");
259  ss << m_blendWeights << "=blendWeights ";
260  return ss.str();
261 } // InterpNatNeighImpl::ToString
262 //------------------------------------------------------------------------------
264 //------------------------------------------------------------------------------
266 {
267  if (m_tris.empty())
268  return;
269 #if _DEBUG
270  std::pair<int, int> pr;
271 #endif
272  for (size_t i = 0; i < m_tris.size(); i += 3)
273  {
274  int k = (int)i;
275  std::pair<int, int> tp[3];
276  EdgesFromTri((int)i, tp);
277  for (int j = 0; j < 3; ++j)
278  {
279  if (m_edges.find(tp[j]) == m_edges.end())
280  {
281  m_edges[tp[j]].first = k;
282  m_edges[tp[j]].second = XM_NONE;
283  }
284  else
285  m_edges[tp[j]].second = k;
286 #if _DEBUG
287  pr = m_edges[tp[j]];
288 #endif
289  }
290  }
291 } // InterpNatNeighImpl::FillEdgeMap
292 //------------------------------------------------------------------------------
294 //------------------------------------------------------------------------------
296 {
297  if (m_pts.empty() || m_tris.empty())
298  return;
299 
300  xms::Pt3d pt, ptMin, ptMax;
301  ptMin = ptMax = m_pts[0];
302  for (size_t i = 1; i < m_pts.size(); ++i)
303  {
304  ptMin.x = Mmin(m_pts[i].x, ptMin.x);
305  ptMin.y = Mmin(m_pts[i].y, ptMin.y);
306  ptMax.x = Mmax(m_pts[i].x, ptMax.x);
307  ptMax.y = Mmax(m_pts[i].y, ptMax.y);
308  }
309  m_tol = gmXyDistance(ptMin, ptMax) / 1e9;
310  m_centers.assign(m_tris.size() / 3, xms::Pt3d());
311  for (size_t i = 0, cnt = 0; i < m_tris.size(); i += 3, ++cnt)
312  {
313  const xms::Pt3d &p0(m_pts[m_tris[i]]), &p1(m_pts[m_tris[i + 1]]), &p2(m_pts[m_tris[i + 2]]);
314  // calculate the center (x,y) and radius squared (z) of the circumcenter
315  // of the triangle
316  gmCircumcircleWithTol(&p0, &p1, &p2, &pt.x, &pt.y, &pt.z, m_tol);
317  m_centers[cnt] = pt;
318  }
319 } // InterpNatNeighImpl::FillCenterVec
320 //------------------------------------------------------------------------------
324 //------------------------------------------------------------------------------
325 void InterpNatNeighImpl::EdgesFromTri(int a_triIdx, std::pair<int, int> a_edges[3])
326 {
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]);
330 } // InterpNatNeighImpl::EdgesFromTri
331 //------------------------------------------------------------------------------
335 //------------------------------------------------------------------------------
336 void InterpNatNeighImpl::NeighTriFromTriIdx(int a_triIdx, std::vector<int>& a_tris)
337 {
338  a_tris.resize(0);
339  std::pair<int, int> edges[3];
340  EdgesFromTri(a_triIdx, edges);
341  std::set<int> setTris;
342  for (int i = 0; i < 3; ++i)
343  {
344  const std::pair<int, int>& pTri = m_edges[edges[i]];
345  setTris.insert(pTri.first);
346  if (XM_NONE != pTri.second)
347  setTris.insert(pTri.second);
348  }
349  setTris.erase(a_triIdx);
350  a_tris.assign(setTris.begin(), setTris.end());
351 } // InterpNatNeighImpl::NeighTriFromTriIdx
352 //------------------------------------------------------------------------------
359 //------------------------------------------------------------------------------
360 void InterpNatNeighImpl::GetNatNeighTriangles(const xms::Pt3d& a_pt, std::vector<int>& a_tris)
361 {
362  a_tris.resize(0);
363  if (!m_triSearch)
364  return;
365  int tIdx = m_triSearch->TriContainingPt(a_pt);
366  if (XM_NONE == tIdx)
367  return;
368 
369  a_tris.push_back(tIdx);
370  std::vector<int> visited(m_tris.size(), 0);
371  visited[tIdx] = 1;
372  for (size_t j = 0; j < a_tris.size(); ++j)
373  {
374  tIdx = a_tris[j];
375  std::vector<int> vals;
376  NeighTriFromTriIdx(tIdx, vals);
377  xms::Pt3d center;
378  double rSquared, distSquared;
379  std::set<int> ptIdxs;
380  // now check to see if the point is inside the circumcircle
381  for (size_t i = 0; i < vals.size(); ++i)
382  {
383  size_t tri = vals[i];
384  if (visited[tri])
385  continue;
386  visited[tri] = 1;
387  distSquared = gmXyDistanceSquared(m_centers[tri / 3], a_pt);
388  rSquared = m_centers[tri / 3].z;
389  if (distSquared <= rSquared)
390  a_tris.push_back((int)tri);
391  }
392  }
393 } // InterpNatNeighImpl::GetNatNeighTriangles
394 //------------------------------------------------------------------------------
398 //------------------------------------------------------------------------------
400 {
401  return ((-2.0 * x * x * x) + (3.0 * x * x));
402 } // InterpNatNeighImpl::BlendFunc
403 //------------------------------------------------------------------------------
408 //------------------------------------------------------------------------------
409 double InterpNatNeighImpl::ScalarFromNodalFunc(int a_ptIdx, const xms::Pt3d& a_loc)
410 {
411  double rval((double)m_scalar[a_ptIdx]);
412  // get value from the nodal function
413  if (m_nf)
414  rval = m_nf->ScalarFromPtIdx(a_ptIdx, a_loc);
415  return rval;
416 } // InterpNatNeighImpl::ScalarFromNodalFunc
417 //------------------------------------------------------------------------------
426 //------------------------------------------------------------------------------
427 double InterpNatNeighImpl::HaleNnInterp(const xms::Pt3d& a_pt)
428 {
429  double rval(0);
430  if (!m_triSearch)
431  return rval;
432  int tIdx = m_triSearch->TriContainingPt(a_pt);
433  if (XM_NONE == tIdx)
434  return rval;
435 
436  std::map<int, double> weights;
437  std::vector<nnOuterEdgeStruct> outerEdges;
438  // search through all neighbors
439  HaleNnVisitNeighbors(tIdx, a_pt, outerEdges, weights);
440  // sort outer edges into a loop
441  HaleNnSortOuterEdges(outerEdges);
442  // process outer edges
443  HaleNnOuterEdgesToWeights(outerEdges, weights);
444 
445  NormalizeWeights(weights);
446  if (m_blendWeights)
447  BlendWeights(weights);
448  rval = ScalarFromWeights(weights, a_pt);
449  return rval;
450 } // InterpNatNeighImpl::HaleNnInterp
451 //------------------------------------------------------------------------------
458 //------------------------------------------------------------------------------
460  const xms::Pt3d& a_pt,
461  std::vector<nnOuterEdgeStruct>& a_outerEdges,
462  std::map<int, double>& a_weights)
463 {
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)
467  { // visit adjacent triangles
468  std::pair<int, int> edge;
469  int tIdx = tris[t];
470  for (int i = 0; i < 3; ++i)
471  {
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);
476  // already processed this edge
477  if (processedEdges.find(edge) != processedEdges.end())
478  continue;
479 
480  // see if there is an adjacent triangle and if it is a natural neighbor
481  int adjTri = AdjacentTriangle(edge, tIdx);
482  if (XM_NONE == adjTri || !PtInTriCircumCircle(a_pt, adjTri))
483  { // no adjtri or not a natural neighbor. This is an outer edge.
484  HaleNnAddOuterEdge(a_outerEdges, tIdx, ptIdx, ptIdx1, a_pt);
485  continue;
486  }
487 
488  // adjacent triangle is a natural neighbor. Calculate area contribution.
489  // cross the circumcenters of the 2 triangles.
490  const xms::Pt3d &tCC(m_centers[tIdx / 3]), adjCC(m_centers[adjTri / 3]);
491  double cross = (tCC.x * adjCC.y) - (tCC.y * adjCC.x);
492  a_weights[ptIdx] -= cross;
493  a_weights[ptIdx1] += cross;
494 
495  tris.push_back(adjTri);
496  // add to processed edges
497  processedEdges.insert(edge);
498  }
499  }
500 } // InterpNatNeighImpl::HaleNnVisitNeighbors
501 //------------------------------------------------------------------------------
507 //------------------------------------------------------------------------------
508 int InterpNatNeighImpl::AdjacentTriangle(std::pair<int, int>& a_edge, int a_triIdx)
509 {
510  int rval = XM_NONE;
511  boost::unordered_map<std::pair<int, int>, std::pair<int, int>>::iterator it(m_edges.find(a_edge));
512  if (it != m_edges.end())
513  {
514  rval = it->second.first;
515  if (a_triIdx == rval)
516  rval = it->second.second;
517  }
518  return rval;
519 } // InterpNatNeighImpl::AdjacentTriangle
520 //------------------------------------------------------------------------------
525 //------------------------------------------------------------------------------
526 bool InterpNatNeighImpl::PtInTriCircumCircle(const xms::Pt3d& a_pt, int a_tri)
527 {
528  const xms::Pt3d& cc = m_centers[a_tri / 3];
529  double d2 = gmXyDistanceSquared(a_pt, cc);
530  if (d2 < cc.z)
531  return true;
532  return false;
533 } // InterpNatNeighImpl::PtInTriCircumCircle
534 //------------------------------------------------------------------------------
541 //------------------------------------------------------------------------------
542 void InterpNatNeighImpl::HaleNnAddOuterEdge(std::vector<nnOuterEdgeStruct>& a_,
543  int a_tIdx,
544  int a_ptIdx0,
545  int a_ptIdx1,
546  const xms::Pt3d& a_pt)
547 {
549  n.m_triIdx = a_tIdx;
550  n.m_edge[0] = a_ptIdx0;
551  n.m_edge[1] = a_ptIdx1;
552  gmCircumcircleWithTol(&m_pts[a_ptIdx0], &m_pts[a_ptIdx1], &a_pt, &n.m_cc.x, &n.m_cc.y, &n.m_cc.z,
553  m_tol);
554  a_.push_back(n);
555 } // InterpNatNeighImpl::HaleNnAddOuterEdge
556 //------------------------------------------------------------------------------
559 //------------------------------------------------------------------------------
560 void InterpNatNeighImpl::HaleNnSortOuterEdges(std::vector<nnOuterEdgeStruct>& a_)
561 {
562  std::vector<nnOuterEdgeStruct> e(a_);
563  for (size_t i = 1; i < a_.size(); ++i)
564  {
565  for (size_t j = 1; j < e.size(); ++j)
566  {
567  if (e[j].m_edge[0] == a_[i - 1].m_edge[1])
568  a_[i] = e[j];
569  }
570  }
571 } // InterpNatNeighImpl::HaleNnSortOuterEdges
572 //------------------------------------------------------------------------------
576 //------------------------------------------------------------------------------
577 void InterpNatNeighImpl::HaleNnOuterEdgesToWeights(std::vector<nnOuterEdgeStruct>& a_outerEdges,
578  std::map<int, double>& a_weights)
579 {
580  for (size_t i = 0; i < a_outerEdges.size(); ++i)
581  { // get the current edge and the next edge
582  nnOuterEdgeStruct& curr(a_outerEdges[i]);
583  size_t nextIdx = i + 1 == a_outerEdges.size() ? 0 : i + 1;
584  nnOuterEdgeStruct& next(a_outerEdges[nextIdx]);
585 
586  int ptIdx = curr.m_edge[1];
587  // cross the original tri cc with the tri cc formed by curr edge and the
588  // interpolation point
589  {
590  xms::Pt3d &o1(m_centers[curr.m_triIdx / 3]), &c1(curr.m_cc);
591  double cross = (o1.x * c1.y) - (o1.y * c1.x);
592  a_weights[ptIdx] += cross;
593  a_weights[curr.m_edge[0]] -= cross;
594  }
595 
596  // cross tri cc formed by curr edge and interp pt with tri cc formed by
597  // next edge and interp pt
598  {
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;
602  }
603  }
604 } // InterpNatNeighImpl::HaleNnOuterEdgesToWeights
605 //------------------------------------------------------------------------------
608 //------------------------------------------------------------------------------
609 void InterpNatNeighImpl::NormalizeWeights(std::map<int, double>& a_weights)
610 {
611  double sum(0);
612  std::map<int, double>::iterator it(a_weights.begin());
613  for (; it != a_weights.end(); ++it)
614  sum += it->second;
615  for (it = a_weights.begin(); it != a_weights.end(); ++it)
616  it->second /= sum;
617 } // InterpNatNeighImpl::NormalizeWeights
618 //------------------------------------------------------------------------------
621 //------------------------------------------------------------------------------
622 void InterpNatNeighImpl::BlendWeights(std::map<int, double>& a_weights)
623 {
624  double sum(0);
625  std::map<int, double>::iterator it(a_weights.begin());
626  for (; it != a_weights.end(); ++it)
627  {
628  it->second = BlendFunc(it->second);
629  sum += it->second;
630  }
631  for (it = a_weights.begin(); it != a_weights.end(); ++it)
632  it->second /= sum;
633 } // InterpNatNeighImpl::NormalizeWeights
634 //------------------------------------------------------------------------------
639 //------------------------------------------------------------------------------
640 double InterpNatNeighImpl::ScalarFromWeights(std::map<int, double>& a_weights,
641  const xms::Pt3d& a_pt)
642 {
643  double rval(0);
644  std::map<int, double>::iterator it(a_weights.begin());
645  for (; it != a_weights.end(); ++it)
646  {
647  rval += it->second * ScalarFromNodalFunc(it->first, a_pt);
648  }
649  return rval;
650 } // InterpNatNeighImpl::NormalizeWeights
651 
652 } // namespace xms
653 
654 #ifdef CXX_TEST
655 
658 
660 
661 namespace
662 {
663 static void iGetPtsTris(std::vector<xms::Pt3d>& a_pts,
664  std::vector<int>& a_tris,
665  std::vector<float>& a_scalar)
666 {
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};
671 } // iGetPtsTris
672 } // unnamed namespace
673 
674 // namespace xms {
675 using namespace xms;
680 //------------------------------------------------------------------------------
682 //------------------------------------------------------------------------------
684 {
685  std::vector<xms::Pt3d> pts;
686  std::vector<int> tris;
687  std::vector<float> scalar;
688  BSHP<InterpNatNeigh> p = InterpNatNeigh::New(pts, tris, scalar, nullptr);
689 } // InterpNatNeighUnitTests::testCreateClass
690 //------------------------------------------------------------------------------
692 //------------------------------------------------------------------------------
694 {
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);
703  InterpNatNeighImpl p(*pts, *tris, scalar, ts.get());
704  p.GetNatNeighTriangles(loc, tIdxs);
705  std::vector<int> nBase = {9, 12, 18, 3};
706  TS_ASSERT_EQUALS_VEC(nBase, tIdxs);
707 } // InterpNatNeighUnitTests::testGetTris
708 //------------------------------------------------------------------------------
710 //------------------------------------------------------------------------------
712 {
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);
720  InterpNatNeighImpl p(*pts, *tris, scalar, ts.get());
721  p.GetNeighbors(6, tIdxs);
722  std::vector<int> nBase = {1, 2, 4, 5};
723  TS_ASSERT_EQUALS_VEC(nBase, tIdxs);
724 } // InterpNatNeighUnitTests::testGetNeighbors
725 //------------------------------------------------------------------------------
727 //------------------------------------------------------------------------------
729 {
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);
748  InterpNatNeighImpl p(*pts, *tris, scalar, ts.get());
749  p.HaleNnSortOuterEdges(edges);
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)
752  {
753  TS_ASSERT_EQUALS(base[i][0], edges[i].m_edge[0]);
754  }
755 } // InterpNatNeighUnitTests::testHaleNnSortOuterEdges
756 //------------------------------------------------------------------------------
758 //------------------------------------------------------------------------------
760 {
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);
768  InterpNatNeighImpl p(*pts, *tris, scalar, ts.get());
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}};
772 
773  std::vector<double> iVals(iPts.size(), 0);
774  for (size_t i = 0; i < iPts.size(); ++i)
775  iVals[i] = p.HaleNnInterp(iPts[i]);
776  std::vector<double> nBase = {6.0669168950546712, 4.6727605118829985, 7.1629642928188586,
777  6.9812628044431957, 8.9941520467836238, 6.9374999999999991,
778  6.6593131032057444, 10.058329876949339};
779  TS_ASSERT_DELTA_VEC(nBase, iVals, 1e-10);
780 } // InterpNatNeighUnitTests::testHaleNnInterp
781 
782 //} // namespace xms
783 #endif // CXX_TEST
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.
#define XM_NONE
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.
_T Mmax(_T a, _U b)
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
_T Mmin(_T a, _U b)
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.
#define TS_ASSERT_EQUALS_VEC(a, b)
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
#define TS_ASSERT_DELTA_VEC(a, b, delta)
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