GteExtremalQuery3BSP.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
13 #include <LowLevel/GteLogger.h>
15 #include <algorithm>
16 #include <stack>
17 #include <queue>
18 
19 namespace gte
20 {
21 
22 template <typename Real>
23 class ExtremalQuery3BSP : public ExtremalQuery3<Real>
24 {
25 public:
26  // Construction.
27  ExtremalQuery3BSP(Polyhedron3<Real> const& polytope);
28 
29  // Disallow copying and assignment.
30  ExtremalQuery3BSP(ExtremalQuery3BSP const&) = delete;
32 
33  // Compute the extreme vertices in the specified direction and return the
34  // indices of the vertices in the polyhedron vertex array.
35  virtual void GetExtremeVertices(Vector3<Real> const& direction,
36  int& positiveDirection, int& negativeDirection) override;
37 
38  // Tree statistics.
39  inline int GetNumNodes() const;
40  inline int GetTreeDepth() const;
41 
42 private:
44  {
45  public:
46  // Construction.
47  SphericalArc();
48 
49  // The arcs are stored in a multiset ordered by increasing separation.
50  // The multiset will be traversed in reverse order. This heuristic is
51  // designed to create BSP trees whose top-most nodes can eliminate as
52  // many arcs as possible during an extremal query.
53  bool operator<(SphericalArc const& arc) const;
54 
55  // Indices N[] into the face normal array for the endpoints of the arc.
56  int nIndex[2];
57 
58  // The number of arcs in the path from normal N[0] to normal N[1].
59  // For spherical polygon edges, the number is 1. The number is 2 or
60  // larger for bisector arcs of the spherical polygon.
62 
63  // The normal is Cross(FaceNormal[N[0]],FaceNormal[N[1]]).
65 
66  // Indices into the vertex array for the extremal points for the
67  // two regions sharing the arc. As the arc is traversed from normal
68  // N[0] to normal N[1], PosVertex is the index for the extreme vertex
69  // to the left of the arc and NegVertex is the index for the extreme
70  // vertex to the right of the arc.
72 
73  // Support for BSP trees stored as contiguous nodes in an array.
75  };
76 
78 
79  void SortAdjacentTriangles(int vIndex,
80  std::set<std::shared_ptr<Triangle>> const& tAdj,
81  std::vector<std::shared_ptr<Triangle>>& tAdjSorted);
82 
83  void CreateSphericalArcs(VETManifoldMesh& mesh, std::multiset<SphericalArc>& arcs);
84  void CreateSphericalBisectors(VETManifoldMesh& mesh, std::multiset<SphericalArc>& arcs);
85  void CreateBSPTree(std::multiset<SphericalArc>& arcs);
86  void InsertArc(SphericalArc const& arcs);
87 
88  // Lookup table for indexing into mFaceNormals.
89  std::map<std::shared_ptr<Triangle>, int> mTriToNormal;
90 
91  // Fixed-size storage for the BSP nodes.
92  std::vector<SphericalArc> mNodes;
94 };
95 
96 template <typename Real>
98  :
99  ExtremalQuery3<Real>(polytope)
100 {
101  // Create the adjacency information for the polytope.
102  VETManifoldMesh mesh;
103  auto const& indices = this->mPolytope.GetIndices();
104  int const numTriangles = static_cast<int>(indices.size() / 3);
105  for (int t = 0; t < numTriangles; ++t)
106  {
107  int V[3];
108  for (int j = 0; j < 3; ++j)
109  {
110  V[j] = indices[3 * t + j];
111  }
112  auto triangle = mesh.Insert(V[0], V[1], V[2]);
113  mTriToNormal.insert(std::make_pair(triangle, t));
114  }
115 
116  // Create the set of unique arcs which are used to create the BSP tree.
117  std::multiset<SphericalArc> arcs;
118  CreateSphericalArcs(mesh, arcs);
119 
120  // Create the BSP tree to be used in the extremal query.
121  CreateBSPTree(arcs);
122 }
123 
124 template <typename Real>
126  int& positiveDirection, int& negativeDirection)
127 {
128  // Do a nonrecursive depth-first search of the BSP tree to determine
129  // spherical polygon contains the incoming direction D. Index 0 is the
130  // root of the BSP tree.
131  int current = 0;
132  while (current >= 0)
133  {
134  SphericalArc& node = mNodes[current];
135  int sign = Function<Real>::ISign(Dot(direction, node.normal));
136  if (sign >= 0)
137  {
138  current = node.posChild;
139  if (current == -1)
140  {
141  // At a leaf node.
142  positiveDirection = node.posVertex;
143  }
144  }
145  else
146  {
147  current = node.negChild;
148  if (current == -1)
149  {
150  // At a leaf node.
151  positiveDirection = node.negVertex;
152  }
153  }
154  }
155 
156  // Do a nonrecursive depth-first search of the BSP tree to determine
157  // spherical polygon contains the reverse incoming direction -D.
158  current = 0; // the root of the BSP tree
159  while (current >= 0)
160  {
161  SphericalArc& node = mNodes[current];
162  int sign = Function<Real>::ISign(Dot(direction, node.normal));
163  if (sign <= 0)
164  {
165  current = node.posChild;
166  if (current == -1)
167  {
168  // At a leaf node.
169  negativeDirection = node.posVertex;
170  }
171  }
172  else
173  {
174  current = node.negChild;
175  if (current == -1)
176  {
177  // At a leaf node.
178  negativeDirection = node.negVertex;
179  }
180  }
181  }
182 }
183 
184 template <typename Real> inline
186 {
187  return static_cast<int>(mNodes.size());
188 }
189 
190 template <typename Real> inline
192 {
193  return mTreeDepth;
194 }
195 
196 template <typename Real>
198  std::set<std::shared_ptr<Triangle>> const& tAdj,
199  std::vector<std::shared_ptr<Triangle>>& tAdjSorted)
200 {
201  // Copy the set of adjacent triangles into a vector container.
202  int const numTriangles = static_cast<int>(tAdj.size());
203  tAdjSorted.resize(tAdj.size());
204 
205  // Traverse the triangles adjacent to vertex V using edge-triangle adjacency
206  // information to produce a sorted array of adjacent triangles.
207  auto tri = *tAdj.begin();
208  for (int i = 0; i < numTriangles; ++i)
209  {
210  for (int prev = 2, curr = 0; curr < 3; prev = curr++)
211  {
212  if (tri->V[curr] == vIndex)
213  {
214  tAdjSorted[i] = tri;
215  tri = tri->T[prev].lock();
216  break;
217  }
218  }
219  }
220 }
221 
222 template <typename Real>
224  std::multiset<SphericalArc>& arcs)
225 {
226  int const prev[3] = { 2, 0, 1 };
227  int const next[3] = { 1, 2, 0 };
228 
229  for (auto const& element : mesh.GetEdges())
230  {
231  auto edge = element.second;
232 
233  SphericalArc arc;
234  arc.nIndex[0] = mTriToNormal[edge->T[0].lock()];
235  arc.nIndex[1] = mTriToNormal[edge->T[1].lock()];
236  arc.separation = 1;
237  arc.normal = Cross(this->mFaceNormals[arc.nIndex[0]], this->mFaceNormals[arc.nIndex[1]]);
238 
239  auto adj = edge->T[0].lock();
240  int j;
241  for (j = 0; j < 3; ++j)
242  {
243  if (adj->V[j] != edge->V[0] && adj->V[j] != edge->V[1])
244  {
245  arc.posVertex = adj->V[prev[j]];
246  arc.negVertex = adj->V[next[j]];
247  break;
248  }
249  }
250  LogAssert(j < 3, "Unexpected condition.");
251 
252  arcs.insert(arc);
253  }
254 
255  CreateSphericalBisectors(mesh, arcs);
256 }
257 
258 template <typename Real>
260  std::multiset<SphericalArc>& arcs)
261 {
262  std::queue<std::pair<int,int>> queue;
263  for (auto const& element : mesh.GetVertices())
264  {
265  // Sort the normals into a counterclockwise spherical polygon when
266  // viewed from outside the sphere.
267  auto vertex = element.second;
268  int const vIndex = vertex->V;
269  std::vector<std::shared_ptr<Triangle>> tAdjSorted;
270  SortAdjacentTriangles(vIndex, vertex->TAdjacent, tAdjSorted);
271  int const numTriangles = static_cast<int>(vertex->TAdjacent.size());
272  queue.push(std::make_pair(0, numTriangles));
273  while (!queue.empty())
274  {
275  std::pair<int, int> item = queue.front();
276  queue.pop();
277  int i0 = item.first, i1 = item.second;
278  int separation = i1 - i0;
279  if (separation > 1 && separation != numTriangles - 1)
280  {
281  if (i1 < numTriangles)
282  {
283  SphericalArc arc;
284  arc.nIndex[0] = mTriToNormal[tAdjSorted[i0]];
285  arc.nIndex[1] = mTriToNormal[tAdjSorted[i1]];
286  arc.separation = separation;
287 
288  arc.normal = Cross(this->mFaceNormals[arc.nIndex[0]],
289  this->mFaceNormals[arc.nIndex[1]]);
290 
291  arc.posVertex = vIndex;
292  arc.negVertex = vIndex;
293  arcs.insert(arc);
294  }
295  int imid = (i0 + i1 + 1) / 2;
296  if (imid != i1)
297  {
298  queue.push(std::make_pair(i0, imid));
299  queue.push(std::make_pair(imid, i1));
300  }
301  }
302  }
303  }
304 }
305 
306 template <typename Real>
307 void ExtremalQuery3BSP<Real>::CreateBSPTree(std::multiset<SphericalArc>& arcs)
308 {
309  // The tree has at least a root.
310  mTreeDepth = 1;
311 
312  for (auto const& arc : gte::reverse(arcs))
313  {
314  InsertArc(arc);
315  }
316 
317  // The leaf nodes are not counted in the traversal of InsertArc. The
318  // depth must be incremented to account for leaves.
319  ++mTreeDepth;
320 }
321 
322 template <typename Real>
324 {
325  // The incoming arc is stored at the end of the nodes array.
326  if (mNodes.size() > 0)
327  {
328  // Do a nonrecursive depth-first search of the current BSP tree to
329  // place the incoming arc. Index 0 is the root of the BSP tree.
330  std::stack<int> candidates;
331  candidates.push(0);
332  while (!candidates.empty())
333  {
334  int current = candidates.top();
335  candidates.pop();
336  SphericalArc* node = &mNodes[current];
337 
338  int sign0;
339  if (arc.nIndex[0] == node->nIndex[0] || arc.nIndex[0] == node->nIndex[1])
340  {
341  sign0 = 0;
342  }
343  else
344  {
345  Real dot = Dot(this->mFaceNormals[arc.nIndex[0]], node->normal);
346  sign0 = Function<Real>::ISign(dot);
347  }
348 
349  int sign1;
350  if (arc.nIndex[1] == node->nIndex[0] || arc.nIndex[1] == node->nIndex[1])
351  {
352  sign1 = 0;
353  }
354  else
355  {
356  Real dot = Dot(this->mFaceNormals[arc.nIndex[1]], node->normal);
357  sign1 = Function<Real>::ISign(dot);
358  }
359 
360  int doTest = 0;
361  if (sign0 * sign1 < 0)
362  {
363  // The new arc straddles the current arc, so propagate it
364  // to both child nodes.
365  doTest = 3;
366  }
367  else if (sign0 > 0 || sign1 > 0)
368  {
369  // The new arc is on the positive side of the current arc.
370  doTest = 1;
371  }
372  else if (sign0 < 0 || sign1 < 0)
373  {
374  // The new arc is on the negative side of the current arc.
375  doTest = 2;
376  }
377  // else: sign0 = sign1 = 0, in which case no propagation is
378  // needed because the current BSP node will handle the correct
379  // partitioning of the arcs during extremal queries.
380 
381  int depth;
382 
383  if (doTest & 1)
384  {
385  if (node->posChild != -1)
386  {
387  candidates.push(node->posChild);
388  depth = static_cast<int>(candidates.size());
389  if (depth > mTreeDepth)
390  {
391  mTreeDepth = depth;
392  }
393  }
394  else
395  {
396  node->posChild = static_cast<int>(mNodes.size());
397  mNodes.push_back(arc);
398 
399  // The push_back can cause a reallocation, so the current
400  // pointer must be refreshed.
401  node = &mNodes[current];
402  }
403  }
404 
405  if (doTest & 2)
406  {
407  if (node->negChild != -1)
408  {
409  candidates.push(node->negChild);
410  depth = static_cast<int>(candidates.size());
411  if (depth > mTreeDepth)
412  {
413  mTreeDepth = depth;
414  }
415  }
416  else
417  {
418  node->negChild = static_cast<int>(mNodes.size());
419  mNodes.push_back(arc);
420  }
421  }
422  }
423  }
424  else
425  {
426  // root node
427  mNodes.push_back(arc);
428  }
429 }
430 
431 template <typename Real>
433  :
434  posChild(-1),
435  negChild(-1)
436 {
437 }
438 
439 template <typename Real>
441 {
442  return separation < arc.separation;
443 }
444 
445 }
virtual void GetExtremeVertices(Vector3< Real > const &direction, int &positiveDirection, int &negativeDirection) override
ExtremalQuery3BSP(Polyhedron3< Real > const &polytope)
EMap const & GetEdges() const
ReversalObject< ReverseIterator > reverse(Iterable &&range)
void CreateBSPTree(std::multiset< SphericalArc > &arcs)
void SortAdjacentTriangles(int vIndex, std::set< std::shared_ptr< Triangle >> const &tAdj, std::vector< std::shared_ptr< Triangle >> &tAdjSorted)
std::map< std::shared_ptr< Triangle >, int > mTriToNormal
#define LogAssert(condition, message)
Definition: GteLogger.h:86
void CreateSphericalBisectors(VETManifoldMesh &mesh, std::multiset< SphericalArc > &arcs)
bool operator<(SphericalArc const &arc) const
VETManifoldMesh::Triangle Triangle
void CreateSphericalArcs(VETManifoldMesh &mesh, std::multiset< SphericalArc > &arcs)
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glcorearb.h:471
GLsizei GLenum const void * indices
Definition: glcorearb.h:401
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble GLdouble t
Definition: glext.h:239
std::vector< Vector3< Real > > mFaceNormals
DualQuaternion< Real > Cross(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
void InsertArc(SphericalArc const &arcs)
static int ISign(Real const &x)
Polyhedron3< Real > const & mPolytope
std::vector< SphericalArc > mNodes
ExtremalQuery3BSP & operator=(ExtremalQuery3BSP const &)=delete
virtual std::shared_ptr< Triangle > Insert(int v0, int v1, int v2) override
VMap const & GetVertices() const


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59