xmsgeom  1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
GmTriSearch.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
10 
11 //----- Included files ---------------------------------------------------------
12 
13 // 1. Precompiled header
14 
15 // 2. My header
17 
18 // 3. Standard Library Headers
19 
20 // 4. External Library Headers
21 #pragma warning(push)
22 #pragma warning(disable : 4512) // boost code: no assignment operator
23 #include <boost/geometry.hpp>
24 #include <boost/geometry/geometries/polygon.hpp>
25 #include <boost/geometry/index/rtree.hpp>
26 #include <boost/unordered_map.hpp>
27 #include <boost/iterator/counting_iterator.hpp>
28 #pragma warning(pop)
29 
30 // 5. Shared Headers
31 #include <xmscore/math/math.h>
32 #include <xmscore/stl/utility.h>
34 #include <xmsgeom/geometry/geoms.h>
36 #include <xmscore/misc/xmstype.h>
37 #include <xmscore/misc/XmError.h>
38 #include <xmscore/misc/XmConst.h>
39 
40 // 6. Non-shared Headers
41 
42 //----- Forward declarations ---------------------------------------------------
43 
44 //----- External globals -------------------------------------------------------
45 
46 //----- Namespace declaration --------------------------------------------------
47 namespace xms
48 {
49 namespace bg = boost::geometry;
50 namespace bgi = bg::index;
51 
52 typedef size_t value;
53 typedef bgi::quadratic<16> qRtree;
54 
55 //----- Constants / Enumerations -----------------------------------------------
56 
57 //----- Classes / Structs ------------------------------------------------------
58 
59 class GmTriSearchImpl;
60 
61 #define BARYTOL 1e-6
62 
63 class idx_tri
65 {
66 public:
67  typedef const GmBstBox3d result_type;
68  explicit idx_tri(const Pt3d* a_pts, const int* a_tris, double a_tol)
73  : m_pts(a_pts)
74  , m_tris(a_tris)
75  , m_tol(a_tol)
76  {
77  }
81  result_type operator()(size_t i) const
82  {
83  i *= 3;
84  const Pt3d& p0(m_pts[m_tris[i]]);
85  const Pt3d& p1(m_pts[m_tris[i + 1]]);
86  const Pt3d& p2(m_pts[m_tris[i + 2]]);
87  GmBstBox3d b;
88  b.max_corner() = b.min_corner() = p0;
89  if (b.min_corner().x > p1.x)
90  b.min_corner().x = p1.x;
91  if (b.min_corner().x > p2.x)
92  b.min_corner().x = p2.x;
93  if (b.max_corner().x < p1.x)
94  b.max_corner().x = p1.x;
95  if (b.max_corner().x < p2.x)
96  b.max_corner().x = p2.x;
97 
98  if (b.min_corner().y > p1.y)
99  b.min_corner().y = p1.y;
100  if (b.min_corner().y > p2.y)
101  b.min_corner().y = p2.y;
102  if (b.max_corner().y < p1.y)
103  b.max_corner().y = p1.y;
104  if (b.max_corner().y < p2.y)
105  b.max_corner().y = p2.y;
106  b.min_corner() -= m_tol;
107  b.max_corner() += m_tol;
108  return b;
109  }
110  const Pt3d* m_pts;
111  const int* m_tris;
112  double m_tol;
113 };
114 
117 {
119  double coef[6];
120  int dir;
121 };
122 
126 {
127 public:
128  GmTriSearchImpl();
129  virtual ~GmTriSearchImpl();
130  virtual void TrisToSearch(BSHP<std::vector<Pt3d>> a_pts, BSHP<std::vector<int>> a_tris) override;
131  virtual void SetPtActivity(DynBitset& a_activity) override;
132  virtual void SetTriActivity(DynBitset& a_activity) override;
135  virtual DynBitset GetPtActivity() override { return PointActivityFromTriActivity(); }
136  bool ActiveTri(int a_idx);
137  virtual int TriContainingPt(const Pt3d& a_pt) override;
138  virtual void TriEnvelopsContainingPt(const Pt3d& a_pt, std::vector<int>& a_tris) override;
139  virtual void TriEnvelopesOverlap(const Pt3d& a_pMin,
140  const Pt3d& a_pMax,
141  std::vector<int>& a_tris) override;
142 
143  virtual bool InterpWeights(const Pt3d& a_pt,
144  std::vector<int>& a_idxs,
145  std::vector<double>& a_wts) override;
146  virtual bool InterpWeightsTriangleIdx(const Pt3d& a_pt,
147  int& a_triangleIdx,
148  std::vector<int>& a_idxs,
149  std::vector<double>& a_wts) override;
150 
151  virtual std::string ToString() const override;
152 
153  void CreateRTree();
154 
155  void PointIdxesFromTriIdx(int a_triIdx, int a_ptIdxes[3]);
156  int FindTriangle(const Pt3d& a_pt, int ix[3], Pt3d& weights);
157  void GetTriBarycentricVals(int a_idx, int a_ix[3], BarycentricVals& a_b);
158 
160  BSHP<GmPtSearch> CreatePtSearch();
161 
164 
165  BSHP<std::vector<Pt3d>> m_pts;
166  BSHP<std::vector<int>> m_tris;
168 
171  boost::unordered_map<size_t, BarycentricVals> m_cache;
173  bgi::rtree<value, qRtree, idx_tri>* m_rTree;
174 };
175 
176 //----- Internal functions -----------------------------------------------------
177 
178 //------------------------------------------------------------------------------
185 //------------------------------------------------------------------------------
186 void iCartToBary(const Pt3d& a_pt1, const Pt3d& a_pt2, const Pt3d& a_pt3, BarycentricVals& a_b)
187 {
188  Pt3d a(a_pt1.x, a_pt1.y, 0.0);
189  Pt3d b(a_pt2.x, a_pt2.y, 0.0);
190  Pt3d c(a_pt3.x, a_pt3.y, 0.0);
191  Pt3d norm(0, 0, 1);
192  gmBaryPrepare(&a, &b, &c, &norm, &a_b.orig, a_b.coef, &a_b.dir, true);
193 } // iCartToBary
194 //------------------------------------------------------------------------------
200 //------------------------------------------------------------------------------
201 void iGetBarycentricCoords(const Pt3d& a_p, BarycentricVals& a_b, Pt3d& weights)
202 {
203  Pt3d p(a_p.x, a_p.y, 0.0);
204  gmCartToBary(&p, &a_b.orig, a_b.coef, a_b.dir, &weights);
205 } // iGetBarycentricCoords
206 
207 //----- Class / Function definitions -------------------------------------------
208 
209 //------------------------------------------------------------------------------
212 //------------------------------------------------------------------------------
213 BSHP<GmTriSearch> GmTriSearch::New()
214 {
215  BSHP<GmTriSearch> ptr(new GmTriSearchImpl());
216  return ptr;
217 } // TriSearch::New
218 //------------------------------------------------------------------------------
220 //------------------------------------------------------------------------------
222 {
223 } // TriSearch::TriSearch
224 //------------------------------------------------------------------------------
226 //------------------------------------------------------------------------------
228 {
229 } // TriSearch::~TriSearch
230 
236 //------------------------------------------------------------------------------
238 //------------------------------------------------------------------------------
240 : m_min(XM_FLT_HIGHEST)
241 , m_max(XM_FLT_LOWEST)
242 , m_pts(new std::vector<Pt3d>())
243 , m_tris(new std::vector<int>())
244 , m_triActivity()
245 , m_rTree(nullptr)
246 {
247 } // GmTriSearchImpl::GmTriSearchImpl
248 //------------------------------------------------------------------------------
250 //------------------------------------------------------------------------------
252 {
253  if (m_rTree)
254  delete (m_rTree);
255 } // GmTriSearchImpl::~GmTriSearchImpl
256 //------------------------------------------------------------------------------
263 //------------------------------------------------------------------------------
264 void GmTriSearchImpl::TrisToSearch(BSHP<std::vector<Pt3d>> a_pts, BSHP<std::vector<int>> a_tris)
265 {
266  // remove existing rtree and cache
267  if (m_rTree)
268  delete (m_rTree);
269  m_cache.clear();
270 
271  m_pts = a_pts;
272  m_tris = a_tris;
273  CreateRTree();
274 } // GmTriSearchImpl::TrisToSearch
275 //------------------------------------------------------------------------------
277 //------------------------------------------------------------------------------
279 {
280  if (m_pts->empty() || m_tris->empty())
281  return;
282 
285  for (size_t i = 0; i < m_pts->size(); ++i)
286  {
287  Pt3d& pt = (*m_pts)[i];
288  if (pt.x < m_min.x)
289  m_min.x = pt.x;
290  if (pt.y < m_min.y)
291  m_min.y = pt.y;
292  if (pt.z < m_min.z)
293  m_min.z = pt.z;
294  if (pt.x > m_max.x)
295  m_max.x = pt.x;
296  if (pt.y > m_max.y)
297  m_max.y = pt.y;
298  if (pt.z > m_max.z)
299  m_max.z = pt.z;
300  }
301  double tol = sqr(m_max.x - m_min.x) + sqr(m_max.y - m_min.y);
302  tol = sqrt(tol) / 1e9;
303 
304  qRtree rtree;
305  size_t nTri = m_tris->size() / 3;
306  idx_tri getter(&(*m_pts)[0], &(*m_tris)[0], tol);
307  m_rTree = new bgi::rtree<size_t, qRtree, idx_tri>(
308  boost::counting_iterator<size_t>(0), boost::counting_iterator<size_t>(nTri), rtree, getter);
309 } // GmTriSearchImpl::CreateRTree
310 //------------------------------------------------------------------------------
313 //------------------------------------------------------------------------------
315 {
316  XM_ENSURE_TRUE_NO_ASSERT(a_activity.size() == m_pts->size());
317 
318  // set triangle activity from point activity
319  m_triActivity.clear();
320  m_triActivity.resize(m_tris->size(), 1);
321  for (size_t i = 0; i < m_tris->size(); i += 3)
322  {
323  if (!a_activity.test((*m_tris)[i]) || !a_activity.test((*m_tris)[i + 1]) ||
324  !a_activity.test((*m_tris)[i + 2]))
325  {
326  m_triActivity[i] = m_triActivity[i + 1] = m_triActivity[i + 2] = 0;
327  }
328  }
329 } // GmTriSearchImpl::SetPtActivity
330 //------------------------------------------------------------------------------
333 //------------------------------------------------------------------------------
335 {
336  if (a_activity.empty())
337  {
338  m_triActivity = a_activity;
339  return;
340  }
341 
342  XM_ENSURE_TRUE_NO_ASSERT(a_activity.size() == m_tris->size() / 3);
343 
344  m_triActivity.reset();
345  m_triActivity.resize(m_tris->size(), 1);
346  size_t idx;
347  for (size_t i = 0; i < a_activity.size(); ++i)
348  {
349  idx = i * 3;
350  m_triActivity[idx + 0] = a_activity[i];
351  m_triActivity[idx + 1] = a_activity[i];
352  m_triActivity[idx + 2] = a_activity[i];
353  }
354 } // GmTriSearchImpl::SetTriActivity
355 //------------------------------------------------------------------------------
360 //------------------------------------------------------------------------------
362 {
363  if (m_triActivity.empty())
364  return true;
365  if (!m_triActivity.test(a_idx))
366  return false;
367  return true;
368 } // GmTriSearchImpl::ActiveTri
369 //------------------------------------------------------------------------------
374 //------------------------------------------------------------------------------
376 {
377  int ix[3];
378  Pt3d weights;
379  return FindTriangle(a_pt, ix, weights);
380 } // GmTriSearchImpl::TriContainingPt
381 //------------------------------------------------------------------------------
385 //------------------------------------------------------------------------------
387 {
388  int idx;
389  a_tris.resize(0);
390  Pt3d p(a_pt.x, a_pt.y, 0);
391  std::vector<value> vals;
392  m_rTree->query(bgi::intersects(p), std::back_inserter(vals));
393  for (size_t i = 0; i < vals.size(); ++i)
394  {
395  idx = (int)(vals[i] * 3);
396  a_tris.push_back(idx);
397  }
398 } // GmTriSearchImpl::TriEnvelopsContainingPt
399 //------------------------------------------------------------------------------
404 //------------------------------------------------------------------------------
405 void GmTriSearchImpl::TriEnvelopesOverlap(const Pt3d& a_pMin, const Pt3d& a_pMax, VecInt& a_tris)
406 {
407  GmBstBox3d bx;
408  bx.max_corner() = a_pMax;
409  bx.max_corner().z = 0;
410  bx.min_corner() = a_pMin;
411  bx.min_corner().z = 0;
412  int idx;
413  a_tris.resize(0);
414  std::vector<value> vals;
415  // m_rTree->query(bgi::overlaps(bx), std::back_inserter(vals));
416  m_rTree->query(bgi::intersects(bx), std::back_inserter(vals));
417  for (size_t i = 0; i < vals.size(); ++i)
418  {
419  idx = (int)(vals[i] * 3);
420  a_tris.push_back(idx);
421  }
422 } // GmTriSearchImpl::TriContainingPt
423 //------------------------------------------------------------------------------
430 //------------------------------------------------------------------------------
431 bool GmTriSearchImpl::InterpWeights(const Pt3d& a_pt, VecInt& a_idxs, VecDbl& a_wts)
432 {
433  int triangleIdx;
434  bool result = InterpWeightsTriangleIdx(a_pt, triangleIdx, a_idxs, a_wts);
435  return result;
436 } // GmTriSearchImpl::InterpWeights
437 //------------------------------------------------------------------------------
446 //------------------------------------------------------------------------------
447 bool GmTriSearchImpl::InterpWeightsTriangleIdx(const Pt3d& a_pt, int& a_triangleIdx,
448  VecInt& a_idxs, VecDbl& a_wts)
449 {
450  int ix[3];
451  Pt3d weights;
452  a_triangleIdx = FindTriangle(a_pt, ix, weights);
453  if (a_triangleIdx != XM_NONE)
454  {
455  a_wts.resize(0);
456  a_wts.push_back(weights.x);
457  a_wts.push_back(weights.y);
458  a_wts.push_back(weights.z);
459  a_idxs.assign(ix, ix + 3);
460  return true;
461  }
462  else
463  {
464  a_idxs.clear();
465  a_wts.clear();
466  }
467  return false;
468 } // GmTriSearchImpl::InterpWeightsTriangleIdx
469 //------------------------------------------------------------------------------
472 //------------------------------------------------------------------------------
473 std::string GmTriSearchImpl::ToString() const
474 {
475  std::stringstream ss;
476  ss << m_min << "=min" << m_max << "=max"
477  << "\n";
478 
479  if (m_pts)
480  VecToStream(ss, *m_pts, "pts");
481  if (m_tris)
482  VecToStream(ss, *m_tris, "tris");
483  VecToStream(ss, m_triActivity, "triActivity");
484  return ss.str();
485 } // GmTriSearchImpl::ToString
486 //------------------------------------------------------------------------------
491 //------------------------------------------------------------------------------
492 void GmTriSearchImpl::PointIdxesFromTriIdx(int a_triIdx, int a_ptIdxes[3])
493 {
494  a_ptIdxes[0] = a_ptIdxes[1] = a_ptIdxes[2] = -1;
495  if (a_triIdx < 0 || a_triIdx + 2 >= (int)m_tris->size())
496  {
497  std::stringstream msg;
498  msg << "Index out of range. File: " << __FILE__ << ", Line:" << __LINE__;
499  XM_LOG(xmlog::debug, msg.str());
500  return;
501  }
502  a_ptIdxes[0] = (*m_tris)[a_triIdx + 0];
503  a_ptIdxes[1] = (*m_tris)[a_triIdx + 1];
504  a_ptIdxes[2] = (*m_tris)[a_triIdx + 2];
505 } // GmTriSearchImpl::PointIdxesFromTriIdx
506 //------------------------------------------------------------------------------
512 //------------------------------------------------------------------------------
513 int GmTriSearchImpl::FindTriangle(const Pt3d& a_pt, int ix[3], Pt3d& weights)
514 {
515  if (!m_tris || m_tris->empty() || !m_pts || m_pts->empty())
516  {
517  XM_LOG(xmlog::error, "Unable to find triangle; no points or triangles exist.");
518  return XM_NONE;
519  }
520  Pt3d p(a_pt.x, a_pt.y, 0);
521  std::vector<value> vals;
522  m_rTree->query(bgi::intersects(p), std::back_inserter(vals));
523  if (vals.empty())
524  return XM_NONE;
525 
526  size_t idx;
527  for (size_t i = 0; i < vals.size(); ++i)
528  {
529  idx = vals[i] * 3;
530  // if any point is inactive then skip this triangle
531  if (!ActiveTri((int)idx))
532  continue;
533  ix[0] = (*m_tris)[idx];
534  ix[1] = (*m_tris)[idx + 1];
535  ix[2] = (*m_tris)[idx + 2];
536 
537  GmBstPoly3d poly;
538  for (size_t j = 0; j < 3; ++j)
539  {
540  bg::exterior_ring(poly).push_back((*m_pts)[ix[j]]);
541  }
542  bg::exterior_ring(poly).push_back((*m_pts)[ix[0]]);
543  if (bg::covered_by(a_pt, poly))
544  {
545  BarycentricVals b;
546  GetTriBarycentricVals((int)idx, ix, b);
547  iGetBarycentricCoords(p, b, weights);
548  return (int)idx;
549  }
550  }
551  // additional checks with some tolerancing
552  for (size_t i = 0; i < vals.size(); ++i)
553  {
554  idx = vals[i] * 3;
555  // if any point is inactive then skip this triangle
556  if (!ActiveTri((int)idx))
557  continue;
558  ix[0] = (*m_tris)[idx];
559  ix[1] = (*m_tris)[idx + 1];
560  ix[2] = (*m_tris)[idx + 2];
561  BarycentricVals b;
562  GetTriBarycentricVals((int)idx, ix, b);
563  iGetBarycentricCoords(p, b, weights);
564  // if (GTEQ_TOL(weights.x, 0, BARYTOL) && GTEQ_TOL(weights.y, 0, BARYTOL) &&
565  // GTEQ_TOL(weights.z, 0, BARYTOL)) {
566  if (weights.x >= -BARYTOL && weights.y >= -BARYTOL && weights.z >= -BARYTOL)
567  {
568  return (int)idx;
569  }
570  }
571 
572  return XM_NONE;
573 } // GmTriSearchImpl::FindTriangle
574 //------------------------------------------------------------------------------
579 //------------------------------------------------------------------------------
580 void GmTriSearchImpl::GetTriBarycentricVals(int a_idx, int a_ix[3], BarycentricVals& a_b)
581 {
582  if (m_cache.find(a_idx) != m_cache.end())
583  {
584  a_b = m_cache[a_idx];
585  }
586  else
587  {
588  iCartToBary((*m_pts)[a_ix[0]], (*m_pts)[a_ix[1]], (*m_pts)[a_ix[2]], a_b);
589  m_cache[a_idx] = a_b;
590  }
591 } // GmTriSearchImpl::GetTriBarycentricVals
592 //------------------------------------------------------------------------------
595 //------------------------------------------------------------------------------
597 {
598  DynBitset r;
599  if (m_triActivity.empty())
600  return r;
601 
602  // all points inactive, if any triangle attached to point is active then
603  // the point will be active
604  r.resize(m_pts->size(), 0);
605  for (size_t i = 0; i < m_tris->size(); i += 3)
606  {
607  if (ActiveTri((int)i))
608  {
609  r[(*m_tris)[i + 0]] = 1;
610  r[(*m_tris)[i + 1]] = 1;
611  r[(*m_tris)[i + 2]] = 1;
612  }
613  }
614  return r;
615 } // GmTriSearchImpl::PointActivityFromTriActivity
616 //------------------------------------------------------------------------------
619 //------------------------------------------------------------------------------
621 {
622  BSHP<GmPtSearch> pts = GmPtSearch::New(true);
623  pts->PtsToSearch(m_pts);
625  pts->SetActivity(b);
626  return pts;
627 } // GmTriSearchImpl::CreatePtSearch
628 
629 } // namespace xms
630 
631 #ifdef CXX_TEST
632 
635 
637 
640 
641 using namespace xms;
642 
647 //------------------------------------------------------------------------------
649 //------------------------------------------------------------------------------
651 {
652  boost::shared_ptr<GmTriSearch> pts = GmTriSearch::New();
653  TS_ASSERT(pts);
654 }
655 //------------------------------------------------------------------------------
657 //------------------------------------------------------------------------------
659 {
660  boost::shared_ptr<GmTriSearch> tris = GmTriSearch::New();
661  BSHP<std::vector<Pt3d>> p(new std::vector<Pt3d>());
662  *p = {{0, 0, 0}, {1, 1, 1}, {1, 0, 2}, {0, 1, 2}, {.5, 1.5, 1}};
663  BSHP<std::vector<int>> t(new std::vector<int>());
664  *t = {0, 2, 1, 0, 1, 3, 3, 1, 4};
665  tris->TrisToSearch(p, t);
666 
667  std::vector<int> idxs, baseIdx;
668  std::vector<double> wt, baseWt;
669  Pt3d pt(.5, .2, 0);
670  TS_ASSERT(tris->InterpWeights(pt, idxs, wt));
671  baseIdx = {0, 2, 1};
672  baseWt = {.5, .3, .2};
673  TS_ASSERT_EQUALS_VEC(baseIdx, idxs);
674  TS_ASSERT_DELTA_VEC(baseWt, wt, 1e-7);
675 
676  int triangleIdx;
677  TS_ASSERT(tris->InterpWeightsTriangleIdx({.25, .75, 0}, triangleIdx, idxs, wt));
678  TS_ASSERT_EQUALS(3, triangleIdx);
679  baseIdx = {0, 1, 3};
680  TS_ASSERT_EQUALS_VEC(baseIdx, idxs);
681  baseWt = {.25, .25, .5};
682  TS_ASSERT_DELTA_VEC(baseWt, wt, 1e-7);
683 
684  TS_ASSERT(!tris->InterpWeightsTriangleIdx({0, 1.25, 0}, triangleIdx, idxs, wt));
685  TS_ASSERT_EQUALS(XM_NONE, triangleIdx);
686  TS_ASSERT_EQUALS_VEC(VecInt(), idxs);
687  TS_ASSERT_DELTA_VEC(VecDbl(), wt, 1e-7);
688 } // TriSearchUnitTests::testInterpWeights
689 //------------------------------------------------------------------------------
691 //------------------------------------------------------------------------------
693 {
694  BSHP<GmTriSearch> tris = GmTriSearch::New();
695  BSHP<std::vector<Pt3d>> p(new std::vector<Pt3d>());
696  *p = {{0, 0, 0}, {1, 1, 1}, {1, 0, 2}, {0, 1, 2}, {.5, 1.5, 1}};
697  BSHP<std::vector<int>> t(new std::vector<int>());
698  *t = {0, 2, 1, 0, 1, 3, 3, 1, 4};
699  tris->TrisToSearch(p, t);
700 
701  DynBitset act_wrongSize(6);
702  // won't do anything
703  tris->SetPtActivity(act_wrongSize);
704 
705  Pt3d pt(.5, .2, 0);
706  TS_ASSERT_EQUALS(0, tris->TriContainingPt(pt));
707 
708  DynBitset act(5);
709  act.flip();
710  act.set(1, false);
711  tris->SetPtActivity(act);
712 
713  TS_ASSERT_EQUALS(XM_NONE, tris->TriContainingPt(pt));
714 } // TriSearchUnitTests::testPtActivity
715 //------------------------------------------------------------------------------
717 //------------------------------------------------------------------------------
719 {
720  BSHP<GmTriSearch> tris = GmTriSearch::New();
721  BSHP<std::vector<Pt3d>> p(new std::vector<Pt3d>());
722  *p = {{0, 0, 0}, {1, 1, 1}, {1, 0, 2}, {0, 1, 2}, {.5, 1.5, 1}};
723  BSHP<std::vector<int>> t(new std::vector<int>());
724  *t = {0, 2, 1, 0, 1, 3, 3, 1, 4};
725  tris->TrisToSearch(p, t);
726 
727  DynBitset act_wrongSize(4);
728  // won't do anything
729  tris->SetTriActivity(act_wrongSize);
730 
731  Pt3d pt(.5, .2, 0), pt2(.5, .5, 0);
732  TS_ASSERT_EQUALS(0, tris->TriContainingPt(pt));
733  // pt2 is right on the boundary between first two triangles
734  TS_ASSERT_EQUALS(0, tris->TriContainingPt(pt2));
735 
736  DynBitset act(3);
737  act.flip();
738  act.set(0, false);
739  tris->SetTriActivity(act);
740 
741  TS_ASSERT_EQUALS(XM_NONE, tris->TriContainingPt(pt));
742  TS_ASSERT_EQUALS(3, tris->TriContainingPt(pt2));
743 
744  // setting to empty activity turns on everything
745  act.clear();
746  tris->SetTriActivity(act);
747  TS_ASSERT_EQUALS(0, tris->TriContainingPt(pt));
748  TS_ASSERT_EQUALS(0, tris->TriContainingPt(pt2));
749 } // TriSearchUnitTests::testPtActivity
750 //------------------------------------------------------------------------------
752 //------------------------------------------------------------------------------
754 {
755  Pt3d pt(-31.459823375717541, 29.927133417260336, 0);
756  GmTriSearchImpl tris;
757  BSHP<std::vector<Pt3d>> p(new std::vector<Pt3d>());
758  *p = {{-20.150000000000002, 46.579999999999998, 7},
759  {-41.100000000000001, 30.370000000000001, 8},
760  {-19.550000000000001, 29.379999999999999, 9}};
761  BSHP<std::vector<int>> t(new std::vector<int>());
762  *t = {2, 0, 1};
763  tris.TrisToSearch(p, t);
764  TS_ASSERT_EQUALS(0, tris.TriContainingPt(pt));
765 } // TriSearchUnitTests::testCase1
766 //------------------------------------------------------------------------------
768 //------------------------------------------------------------------------------
770 {
771  Pt3d pt(.5, .5, 0);
772  GmTriSearchImpl tris;
773  BSHP<std::vector<Pt3d>> p(new std::vector<Pt3d>());
774  *p = {{0, 0, 7}, {1, 0, 8}, {1, 1, 9}};
775  BSHP<std::vector<int>> t(new std::vector<int>());
776  *t = {2, 0, 1};
777  tris.TrisToSearch(p, t);
778  TS_ASSERT_EQUALS(0, tris.TriContainingPt(pt));
779 } // TriSearchUnitTests::testTouch
780 //------------------------------------------------------------------------------
782 //------------------------------------------------------------------------------
784 {
785  BSHP<TrTin> t = trBuildTestTin();
786  GmTriSearchImpl ts;
787  BSHP<VecInt> tPtr(new VecInt());
788  tPtr->reserve(t->Triangles().size());
789  for (const auto& tt : t->Triangles())
790  tPtr->push_back((int)tt);
791  ts.TrisToSearch(t->PointsPtr(), tPtr);
792 
793  Pt3d pMin(9, 4, 0), pMax(15, 10, 0);
794  VecInt tIdxes;
795  ts.TriEnvelopesOverlap(pMin, pMax, tIdxes);
796  std::sort(tIdxes.begin(), tIdxes.end());
797  VecInt baseIdxes = {3, 6, 9, 18, 21, 27};
798  TS_ASSERT_EQUALS_VEC(baseIdxes, tIdxes);
799 } // TriSearchUnitTests::testTriEnvelopesOverlap
800 
801 #endif // CXX_TEST
provides indexing for the spatial index
Definition: GmTriSearch.cpp:64
#define XM_LOG(A, B)
virtual void TriEnvelopsContainingPt(const Pt3d &a_pt, std::vector< int > &a_tris) override
Find all triangle whose envelop contains the point.
DynBitset PointActivityFromTriActivity()
Gets the activity of the points from the triangles.
virtual void TrisToSearch(BSHP< std::vector< Pt3d >> a_pts, BSHP< std::vector< int >> a_tris) override
Adds the triangles to the class.
#define XM_NONE
void testPtActivity()
tests setting the point activity
#define BARYTOL
This is an odd duck tolerance.
Definition: GmTriSearch.cpp:61
Structure for Barycentric coordinate calculations.
virtual ~GmTriSearchImpl()
Destructor.
BSHP< std::vector< Pt3d > > m_pts
point locations
virtual void TriEnvelopesOverlap(const Pt3d &a_pMin, const Pt3d &a_pMax, std::vector< int > &a_tris) override
Find all triangle whose envelop contains the point.
boost::geometry types
BSHP< std::vector< int > > m_tris
triangles that reference point indexes
static BSHP< GmTriSearch > New()
Creates an TriSearch class.
BSHP< TrTin > trBuildTestTin()
Builds a simple TIN with a hole in the middle.
Definition: TrTin.cpp:1351
int FindTriangle(const Pt3d &a_pt, int ix[3], Pt3d &weights)
Find the triangle containing the location a_pt.
const GmBstBox3d result_type
Definition: GmTriSearch.cpp:67
#define XM_ENSURE_TRUE_NO_ASSERT(...)
DynBitset m_triActivity
activity of the triangles
An intersection point of a line with a polygon.
Spatial index for searching triangles.
Definition: GmTriSearch.h:30
result_type operator()(size_t i) const
calculates triangle extents based on a triangle index
Definition: GmTriSearch.cpp:81
void testCreateClass()
tests creating the class
std::vector< int > VecInt
const Pt3d * m_pts
point locations
void VecToStream(std::stringstream &a_ss, const T &a_v, std::string a_label)
void testInterpWeights()
tests calculation of interpolation weights from triangles
double coef[6]
barycentric coefficients
boost::unordered_map< size_t, BarycentricVals > m_cache
Functions dealing with geometry.
void testTriEnvelopesOverlap()
tests overlaping triangles
Pt3d m_max
maximum extents of all points
double m_tol
tolerance used to expand extents of triangle
const int * m_tris
triangles referencing point indexes
std::vector< double > VecDbl
idx_tri(const Pt3d *a_pts, const int *a_tris, double a_tol)
Definition: GmTriSearch.cpp:72
boost::dynamic_bitset< size_t > DynBitset
virtual bool InterpWeightsTriangleIdx(const Pt3d &a_pt, int &a_triangleIdx, std::vector< int > &a_idxs, std::vector< double > &a_wts) override
Use the stored triangles to get interpolation weights for a point. Returns false if the point is outs...
Pt3d orig
original point location
static const float XM_FLT_HIGHEST
#define BSHP
void GetTriBarycentricVals(int a_idx, int a_ix[3], BarycentricVals &a_b)
Gets the barycentric values for a triangle.
_T sqr(const _T x)
Pt3d m_min
mininum extents of all points
static BSHP< GmPtSearch > New(bool a_2dSearch)
Creates an PtSearch class.
Definition: GmPtSearch.cpp:236
GmTriSearchImpl()
Constructor.
virtual void SetTriActivity(DynBitset &a_activity) override
Modifies the activity bitset of the class.
virtual bool InterpWeights(const Pt3d &a_pt, std::vector< int > &a_idxs, std::vector< double > &a_wts) override
Use the stored triangles to get interpolation weights for a point. Returns false if the point is outs...
BSHP< GmPtSearch > CreatePtSearch()
creates the rtree of the points
virtual void SetPtActivity(DynBitset &a_activity) override
Modifies the activity bitset of the class.
GmTriSearch()
Constructor.
bool ActiveTri(int a_idx)
Tests if a triangle is active. If any of the points of the tri are not active then the tri is not act...
virtual int TriContainingPt(const Pt3d &a_pt) override
Find the triangle containing the point.
bgi::rtree< value, qRtree, idx_tri > * m_rTree
spatial index of the triangle extents
#define TS_ASSERT_EQUALS_VEC(a, b)
int dir
direction based on the xyz's of the points making the triangle
virtual ~GmTriSearch()
Destructor.
void testSmsCase1()
A particular test case from SMS that was included.
virtual DynBitset GetPtActivity() override
Activity of the points based on the triangle activity.
void testTriActivity()
tests setting the triangle activity
void testTouch()
tests a point that touches a triangle
#define TS_ASSERT_DELTA_VEC(a, b, delta)
virtual std::string ToString() const override
Write the internals to a string.
Implementation of GmTriSearch.
void PointIdxesFromTriIdx(int a_triIdx, int a_ptIdxes[3])
Fills in the point indices based on the triangle index.
static const float XM_FLT_LOWEST
void CreateRTree()
Creates the RTree of the triangles.