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