Nektar++
Octree.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: Octree.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: Implementation of an octree sorting algorithm.
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include "Octree.h"
36#include <cmath>
37#include <stdexcept>
38
39namespace Nektar::FieldUtils
40{
41
42/**
43 * @brief Construct a new octree object
44 *
45 */
47 : m_maxPts(0), m_nMshPts(0), m_nNodes(0), m_nLeaves(0), m_maxDepth(0),
48 m_root(nullptr)
49{
50}
51
52/**
53 * @brief Construct a new octree object
54 *
55 * @param pts
56 * @param maxPts
57 * @param bounds
58 */
60 const Array<OneD, NekDouble> &bounds)
61{
62 // Set some values
63 m_maxPts = maxPts;
64 m_nMshPts = pts.size();
65
66 // Create first (root) node
67 std::vector<int> indices(m_nMshPts);
68 for (int i = 0; i < m_nMshPts; ++i)
69 {
70 indices[i] = i;
71 }
72 m_root = std::make_shared<Octant>(0, 1, 0, bounds);
73 m_root->SetIndices(indices);
74 m_nodes.push_back(m_root);
75
76 // Create the tree
77 m_root->Subdivide(m_maxPts, pts, m_nodes);
78
79 // Get some data after the tree is computed
80 m_maxDepth = 0;
81 AdvanceToStats(m_root->GetID());
82 m_nNodes = m_nodes.size();
83
84 // Set the pointers to the neighbouring nodes
85 SetNeighbours(m_root->GetID());
86}
87
88/**
89 * @brief Construct a new octree object
90 *
91 * @param pts
92 * @param maxPts
93 */
95{
96 // Small margin to avoid rounding errors
97 NekDouble margin = 1e-10;
98
99 // Find coordinates of the bounding box
100 Array<OneD, NekDouble> bounds(6);
101 bounds[0] = pts[0][0];
102 bounds[1] = pts[0][0];
103 bounds[2] = pts[0][1];
104 bounds[3] = pts[0][1];
105 bounds[4] = pts[0][2];
106 bounds[5] = pts[0][2];
107 for (int i = 1; i < m_nMshPts; ++i)
108 {
109 bounds[0] = (bounds[0] < pts[i][0]) ? bounds[0] : pts[i][0];
110 bounds[1] = (bounds[1] > pts[i][0]) ? bounds[1] : pts[i][0];
111 bounds[2] = (bounds[2] < pts[i][1]) ? bounds[2] : pts[i][1];
112 bounds[3] = (bounds[3] > pts[i][1]) ? bounds[3] : pts[i][1];
113 bounds[4] = (bounds[4] < pts[i][2]) ? bounds[4] : pts[i][2];
114 bounds[5] = (bounds[5] > pts[i][2]) ? bounds[5] : pts[i][2];
115 }
116
117 // Add the margin
118 for (int i = 0; i < 6; ++i)
119 {
120 bounds[i] -= pow(-1, i) * margin;
121 }
122
123 // Call the octree constructor
124 Octree(pts, maxPts, bounds);
125}
126
127/**
128 * @brief Given the coordinates 'coords' of a point, returns the leaf octant
129 * that contains it. If 'depth' is specified, returs the node that contains the
130 * point such that its depth is lower or equal to the one indicated. If the
131 * point lies outside the tree, it returns -1
132 *
133 * @param coords
134 * @param depth
135 * @return int
136 */
137int Octree::QueryNode(const Array<OneD, NekDouble> &coords, int depth)
138{
139 int nodeID = -1;
140
141 if (coords.size())
142 {
143 // First, check if inside the octree
144 Array<OneD, NekDouble> bounds = m_root->GetBounds();
145 if ((coords[0] >= bounds[0]) && (coords[0] <= bounds[1]) &&
146 (coords[1] >= bounds[2]) && (coords[1] <= bounds[3]) &&
147 (coords[2] >= bounds[4]) && (coords[2] <= bounds[5]))
148 {
149 // Initialise 'node'
150 OctantSharedPtr node = m_root;
151
152 // Keep advancing towards the end of the branch
153 while (!node->IsLeaf() && node->GetDepth() < depth)
154 {
155 int loc = node->GetLocInNode(coords);
156 node = node->GetChildren()[loc - 1];
157 }
158
159 nodeID = node->GetID();
160 }
161 }
162
163 return nodeID;
164}
165
166/**
167 * @brief Finds the ID of the closest point in 'pts' to the one specified by
168 * 'coords'. It also returns the distance between both points in 'distance'
169 *
170 * @param pts
171 * @param coords
172 * @param distance
173 * @param pointInd
174 * @return int
175 */
177 const Array<OneD, NekDouble> &coords,
178 NekDouble &distance, int pointInd)
179{
180 int index = -1;
181 distance = std::numeric_limits<NekDouble>::max();
182
183 if (coords.size())
184 {
185 // Find the corresponding node to 'coords'
186 int nodeInd;
187 if (pointInd > 0)
188 {
189 nodeInd = pointInd;
190 }
191 else
192 {
193 nodeInd = QueryNode(coords);
194 }
195
196 // List the indices of all the candidate points
197 std::vector<int> indices(m_nodes[nodeInd]->GetIndices());
198 for (OctantWeakPtr neigh : m_nodes[nodeInd]->GetNeighbours())
199 {
200 for (int i : neigh.lock()->GetIndices())
201 {
202 indices.push_back(i);
203 }
204 }
205
206 // Check the distances with all the nodes
207 for (int i : indices)
208 {
209 NekDouble sub = pts[i][0] - coords[0];
210 NekDouble tmpDistance = sub * sub;
211 for (int j = 1; j < 3; ++j)
212 {
213 sub = pts[i][j] - coords[j];
214 tmpDistance += sub * sub;
215 }
216 tmpDistance = std::sqrt(tmpDistance);
217
218 if (distance > tmpDistance)
219 {
220 distance = tmpDistance;
221 index = i;
222 }
223 }
224 }
225
226 return index;
227}
228
229/**
230 * @brief Returns the indices of the points of the mesh contained in the tree
231 *
232 * @param nodeID
233 * @return std::vector<int>
234 */
235std::vector<int> Octree::QueryPoints(int nodeID)
236{
237 return m_nodes[nodeID]->GetIndices();
238}
239
240/**
241 * @brief Returns the IDs of the octants that surround the queried node. First,
242 * it finds the neighbouring nodes with the same or lower depth and, if they
243 * are not leaf nodes, return all the leaf octants contained in them. This
244 * means that, for octants of depth 2, this function returns all the leaf nodes
245 * in the tree except those lying inside the queried octant
246 *
247 * @param nodeID
248 * @return std::vector<int>
249 */
250std::vector<int> Octree::QueryNeighbours(int nodeID)
251{
252 std::vector<int> indices;
253 for (const OctantWeakPtr &node : m_nodes[nodeID]->GetNeighbours())
254 {
255 indices.push_back(node.lock()->GetID());
256 }
257 return indices;
258}
259
260/**
261 * @brief Returns some characteristic values of the tree.
262 *
263 * @param maxPts
264 * @param nPts
265 * @param nNodes
266 * @param nLeaves
267 * @param depth
268 */
269void Octree::GetStats(int &maxPts, int &nPts, int &nNodes, int &nLeaves,
270 int &depth)
271{
272 maxPts = m_maxPts;
273 nPts = m_nMshPts;
274 nNodes = m_nNodes;
275 nLeaves = m_nLeaves;
276 depth = m_maxDepth;
277}
278
279/**
280 * @brief Goes through all the nodes of the octree counting the number of
281 * octants and the maximum depth reached
282 *
283 * @param nodeID
284 */
286{
287 // Update stats if we reached the end of the branch
288 if (m_nodes[nodeID]->IsLeaf())
289 {
290 m_nLeaves++;
291 m_maxDepth = (m_maxDepth > m_nodes[nodeID]->GetDepth())
292 ? m_maxDepth
293 : m_nodes[nodeID]->GetDepth();
294 }
295 // In any other case, dig into the tree
296 else
297 {
298 Array<OneD, OctantSharedPtr> children = m_nodes[nodeID]->GetChildren();
299 for (OctantSharedPtr child : children)
300 {
301 AdvanceToStats(child->GetID());
302 }
303 }
304}
305
306/**
307 * @brief Once the nodes of the octree are created, sets their neighbours as
308 * explained in 'Octree::QueryNeighbours'
309 *
310 * @param nodeID
311 */
312void Octree::SetNeighbours(int nodeID)
313{
314 // Array with the different steps
315 static int steps[26][3] = {
316 {-1, -1, -1}, {1, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 1, 0},
317 {-1, 0, 0}, {-1, 0, 0}, {0, -1, 0}, {1, 0, 0}, {-1, -1, 1},
318 {1, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 1, 0}, {-1, 0, 0},
319 {-1, 0, 0}, {0, -1, 0}, {0, -1, 1}, {1, 0, 0}, {1, 0, 0},
320 {0, 1, 0}, {0, 1, 0}, {-1, 0, 0}, {-1, 0, 0}, {0, -1, 0},
321 {1, 0, 0}};
322
323 // Advance to the leaves of the octree
324 if (!m_nodes[nodeID]->IsLeaf())
325 {
326 for (OctantSharedPtr child : m_nodes[nodeID]->GetChildren())
327 {
328 SetNeighbours(child->GetID());
329 }
330 }
331 else
332 {
333 // delta * steps
334 Array<OneD, NekDouble> probeCoords(m_nodes[nodeID]->GetCentre());
335 for (int step = 0; step < 26; ++step)
336 {
337 for (int i = 0; i < 3; ++i)
338 {
339 probeCoords[i] += m_nodes[nodeID]->GetDelta() * steps[step][i];
340 }
341
342 // For each neighbour, find the leaves and add them
343 int neighInd = QueryNode(probeCoords, m_nodes[nodeID]->GetDepth());
344 if (neighInd > -1)
345 {
346 std::vector<OctantSharedPtr> leaves;
347 m_nodes[neighInd]->GetLeaves(leaves);
348 m_nodes[nodeID]->AddNeighbours(leaves);
349 }
350 }
351 }
352}
353
354/**
355 * @brief Construct a new Octree::Octant object
356 *
357 */
359 : m_nPts(-1), m_loc(-1), m_depth(-1), m_id(-1), m_delta(-1), m_centre(3),
360 m_bounds(6), m_isLeaf(true)
361{
362}
363
364/**
365 * @brief Construct a new Octree::Octant object
366 *
367 * @param loc
368 * @param depth
369 * @param id
370 * @param bounds
371 */
372Octree::Octant::Octant(int loc, int depth, int id,
373 const Array<OneD, NekDouble> &bounds)
374 : m_nPts(0), m_loc(loc), m_depth(depth), m_id(id), m_isLeaf(true)
375{
376 // Check the size of 'bounds'
377 if (bounds.size() != 6)
378 {
379 throw std::out_of_range("Size of bounds must be 6.");
380 }
381
382 // If all deltas are not equal, use the largest ones
383 NekDouble deltaX = bounds[1] - bounds[0];
384 NekDouble deltaY = bounds[3] - bounds[2];
385 NekDouble deltaZ = bounds[5] - bounds[4];
386 if (deltaX != deltaY || deltaY != deltaZ)
387 {
388 m_delta = (deltaX > deltaY) ? deltaX : deltaY;
389 m_delta = (m_delta > deltaZ) ? m_delta : deltaZ;
390 }
391 else
392 {
393 m_delta = deltaX;
394 }
395
396 // Fill in the rest of the data
399 for (int i = 0; i < 3; ++i)
400 {
401 m_centre[i] = (bounds[2 * i + 1] + bounds[2 * i]) / 2.0;
402 m_bounds[2 * i] = m_centre[i] - m_delta / 2.0;
403 m_bounds[2 * i + 1] = m_centre[i] + m_delta / 2.0;
404 }
405}
406
407/**
408 * @brief Construct a new Octree::Octant object
409 *
410 * @param loc
411 * @param parent
412 */
414 : m_nPts(0), m_loc(loc), m_id(-1), m_isLeaf(true)
415{
416 // Set depth
417 m_depth = parent.GetDepth() + 1;
418
419 // Set delta
420 m_delta = parent.GetDelta() / 2.0;
421
422 // Set centre
423 NekDouble centreDX;
424 NekDouble centreDY;
425 NekDouble centreDZ;
426 switch (loc)
427 {
428 case 1: // x-, y-, z-
429 centreDX = -m_delta / 2.0;
430 centreDY = -m_delta / 2.0;
431 centreDZ = -m_delta / 2.0;
432 break;
433 case 2: // x+, y-, z-
434 centreDX = m_delta / 2.0;
435 centreDY = -m_delta / 2.0;
436 centreDZ = -m_delta / 2.0;
437 break;
438 case 3: // x+, y+, z-
439 centreDX = m_delta / 2.0;
440 centreDY = m_delta / 2.0;
441 centreDZ = -m_delta / 2.0;
442 break;
443 case 4: // x-, y+, z-
444 centreDX = -m_delta / 2.0;
445 centreDY = m_delta / 2.0;
446 centreDZ = -m_delta / 2.0;
447 break;
448 case 5: // x-, y-, z+
449 centreDX = -m_delta / 2.0;
450 centreDY = -m_delta / 2.0;
451 centreDZ = m_delta / 2.0;
452 break;
453 case 6: // x+, y-, z+
454 centreDX = m_delta / 2.0;
455 centreDY = -m_delta / 2.0;
456 centreDZ = m_delta / 2.0;
457 break;
458 case 7: // x+, y+, z+
459 centreDX = m_delta / 2.0;
460 centreDY = m_delta / 2.0;
461 centreDZ = m_delta / 2.0;
462 break;
463 case 8: // x-, y+, z+
464 centreDX = -m_delta / 2.0;
465 centreDY = m_delta / 2.0;
466 centreDZ = m_delta / 2.0;
467 break;
468 default:
469 throw std::out_of_range("Loc must be in the range (1,8).");
470 }
471 Array<OneD, NekDouble> pCentre = parent.GetCentre();
473 m_centre[0] = pCentre[0] + centreDX;
474 m_centre[1] = pCentre[1] + centreDY;
475 m_centre[2] = pCentre[2] + centreDZ;
476
477 // Set bounds
479 for (int i = 0; i < 3; ++i)
480 {
481 m_bounds[2 * i] = m_centre[i] - m_delta / 2.0;
482 m_bounds[2 * i + 1] = m_centre[i] + m_delta / 2.0;
483 }
484}
485
486/**
487 * @brief Updates 'leaves' so that it contains all the leaf nodes belonging to
488 * the octant
489 *
490 * @param leaves
491 */
492void Octree::Octant::GetLeaves(std::vector<OctantSharedPtr> &leaves)
493{
494 if (m_isLeaf)
495 {
496 leaves.push_back(shared_from_this());
497 }
498 else
499 {
500 for (OctantSharedPtr child : m_children)
501 {
502 child->GetLeaves(leaves);
503 }
504 }
505}
506
507/**
508 * @brief Sets the values of 'm_pointInd' to those in 'indices'
509 *
510 * @param indices
511 */
512void Octree::Octant::SetIndices(const std::vector<int> &indices)
513{
514 for (int i : indices)
515 {
516 m_pointInd.push_back(i);
517 }
518 m_nPts = indices.size();
519}
520
521/**
522 * @brief Adds to 'm_neighbours' the octants that are not already in the list
523 *
524 * @param neighbours
525 */
527 const std::vector<OctantSharedPtr> &neighbours)
528{
529 for (const OctantSharedPtr &neighbour : neighbours)
530 {
531 bool equal = false;
532 for (const OctantWeakPtr &neigh : m_neighbours)
533 {
534 if (neigh.lock()->GetID() == neighbour->GetID())
535 {
536 equal = true;
537 break;
538 }
539 }
540 if (!equal)
541 {
542 m_neighbours.push_back(neighbour);
543 }
544 }
545}
546
547/**
548 * @brief Adds to 'm_pointInd' the IDs of the points in 'pts' that fall inside
549 * the octant
550 *
551 * @param pts
552 * @param indices
553 */
555 const std::vector<int> &indices)
556{
557 for (int i : indices)
558 {
559 // Check if the point is inside the node
560 Array<OneD, NekDouble> pt = pts[i];
561 if ((pt[0] < m_bounds[0]) || (pt[0] > m_bounds[1]))
562 {
563 continue;
564 }
565 if ((pt[1] < m_bounds[2]) || (pt[1] > m_bounds[3]))
566 {
567 continue;
568 }
569 if ((pt[2] < m_bounds[4]) || (pt[2] > m_bounds[5]))
570 {
571 continue;
572 }
573
574 // If so, add it to the list
575 m_nPts++;
576 m_pointInd.push_back(i);
577
578 // Flag it as a leaf node
579 m_isLeaf = true;
580 }
581}
582
583/**
584 * @brief Recursively divides the octant into 8 children and fills the leaf
585 * nodes with their corresponding points. Does NOT add neighbours
586 *
587 * @param maxPts
588 * @param pts
589 * @param nodes
590 */
592 const Array<OneD, Array<OneD, NekDouble>> &pts,
593 std::vector<OctantSharedPtr> &nodes)
594{
595 // For a non-leaf node
596 if (m_nPts > maxPts)
597 {
598 // Create and fill children RECURSIVELY
599 m_children = Array<OneD, OctantSharedPtr>(8);
600 for (int i = 0; i < 8; ++i)
601 {
602 OctantSharedPtr newChild =
603 std::make_shared<Octant>(i + 1, *shared_from_this());
604 newChild->AddPoints(pts, m_pointInd);
605 newChild->SetID(nodes.size()); // ID's start from 0
606
607 // Add it to the list
608 m_children[i] = newChild;
609 nodes.push_back(newChild);
610
611 // Keep dividing
612 newChild->Subdivide(maxPts, pts, nodes); // Recursion
613 }
614
615 // Not a leaf node anymore
616 m_pointInd.clear();
617 m_nPts = 0;
618 m_isLeaf = false;
619 }
620}
621
622/**
623 * @brief Returns the position inside an octant in the range (1-8). The name
624 * convention is as follows: let \f$\Delta\f$ be a value between 0 and the
625 * length of the side of the father octant, and \f$x_c,y_c,z_c\f$ be the
626 * coordinates of the centre of the father node. Then, position 1 corresponds
627 * to \f$x=x_c-\Delta\f$, \f$y=y_c-\Delta\f$ and \f$y=y_c-\Delta\f$. The next
628 * positions are obtained by rotating counter-clockwise around the Z axis and
629 * then, making the same rotation for \f$z=z_c+\Delta\f$
630 *
631 * @param coords
632 * @return int
633 */
635{
636 // Different positions as bits in 'posByte'
637 // MSB <==> LSB
638 unsigned char posByte;
639
640 if (coords[0] <= m_centre[0]) // x-
641 {
642 posByte = 153; // 0b10011001;
643 }
644 else // x+
645 {
646 posByte = 102; // 0b01100110;
647 }
648 if (coords[1] <= m_centre[1]) // y-
649 {
650 posByte &= 51; // 0b00110011;
651 }
652 else // y+
653 {
654 posByte &= 204; // 0b11001100;
655 }
656 if (coords[2] <= m_centre[2]) // z-
657 {
658 posByte &= 15; // 0b00001111;
659 }
660 else // z+
661 {
662 posByte &= 240; // 0b11110000;
663 }
664
665 // Transform into a position in the range (1,8)
666 int position = 1;
667 while (posByte > 1)
668 {
669 posByte = posByte >> 1;
670 position++;
671 }
672
673 return position;
674}
675} // namespace Nektar::FieldUtils
Array< OneD, NekDouble > & GetCentre()
Definition: Octree.h:128
Array< OneD, NekDouble > m_centre
Coordinates of the centre of the octant.
Definition: Octree.h:176
void AddPoints(const Array< OneD, Array< OneD, NekDouble > > &pts, const std::vector< int > &indices)
Adds to 'm_pointInd' the IDs of the points in 'pts' that fall inside the octant.
Definition: Octree.cpp:554
int m_depth
Depth in octree (root is 1)
Definition: Octree.h:170
double m_delta
Length of the octant side.
Definition: Octree.h:174
void AddNeighbours(const std::vector< OctantSharedPtr > &neighbours)
Adds to 'm_neighbours' the octants that are not already in the list.
Definition: Octree.cpp:526
void GetLeaves(std::vector< OctantSharedPtr > &leaves)
Updates 'leaves' so that it contains all the leaf nodes belonging to the octant.
Definition: Octree.cpp:492
void SetIndices(const std::vector< int > &indices)
Sets the values of 'm_pointInd' to those in 'indices'.
Definition: Octree.cpp:512
void Subdivide(int maxPts, const Array< OneD, Array< OneD, NekDouble > > &pts, std::vector< OctantSharedPtr > &nodes)
Recursively divides the octant into 8 children and fills the leaf nodes with their corresponding poin...
Definition: Octree.cpp:591
Array< OneD, NekDouble > m_bounds
Min/max coordinates of the octant (x, y, z)
Definition: Octree.h:178
int GetLocInNode(const Array< OneD, NekDouble > &coords)
Returns the position inside an octant in the range (1-8). The name convention is as follows: let be ...
Definition: Octree.cpp:634
Octant()
Construct a new Octree::Octant object.
Definition: Octree.cpp:358
void SetNeighbours(int nodeID)
Once the nodes of the octree are created, sets their neighbours as explained in 'Octree::QueryNeighbo...
Definition: Octree.cpp:312
OctantSharedPtr m_root
First node of the tree, linked to the rest.
Definition: Octree.h:202
std::vector< int > QueryNeighbours(int nodeID)
Returns the IDs of the octants that surround the queried node. First, it finds the neighbouring nodes...
Definition: Octree.cpp:250
std::vector< int > QueryPoints(int nodeID)
Returns the indices of the points of the mesh contained in the tree.
Definition: Octree.cpp:235
int m_nNodes
Number of octants in the tree.
Definition: Octree.h:195
void GetStats(int &maxPts, int &nPts, int &nNodes, int &nLeaves, int &depth)
Returns some characteristic values of the tree.
Definition: Octree.cpp:269
int m_nLeaves
Number of leaf nodes in the tree.
Definition: Octree.h:197
std::shared_ptr< Octant > OctantSharedPtr
Definition: Octree.h:46
int QueryClosest(const Array< OneD, Array< OneD, NekDouble > > &pts, const Array< OneD, NekDouble > &coords, double &distance, int pointInd=-1)
Finds the ID of the closest point in 'pts' to the one specified by 'coords'. It also returns the dist...
Definition: Octree.cpp:176
std::weak_ptr< Octant > OctantWeakPtr
Definition: Octree.h:47
int m_maxPts
Max points allowed in each octant.
Definition: Octree.h:191
int m_maxDepth
Maximum depth of the tree.
Definition: Octree.h:199
void AdvanceToStats(int nodeID)
Goes through all the nodes of the octree counting the number of octants and the maximum depth reached...
Definition: Octree.cpp:285
Octree()
Construct a new octree object.
Definition: Octree.cpp:46
int m_nMshPts
Number of points in the mesh.
Definition: Octree.h:193
std::vector< OctantSharedPtr > m_nodes
Vector of pointers to every octant in the tree.
Definition: Octree.h:204
int QueryNode(const Array< OneD, NekDouble > &coords, int depth=std::numeric_limits< int >::max())
Given the coordinates 'coords' of a point, returns the leaf octant that contains it....
Definition: Octree.cpp:137
double NekDouble
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294