Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
TetrahedralTree.cc
Go to the documentation of this file.
2#include <iostream>
3
4namespace Garfield {
5
6std::vector<int> TetrahedralTree::emptyBlock = {};
7
8/**
9TetrahedralTree.cc
10This class stores the mesh nodes and elements in an Octree data
11structure to optimize the element search operations
12
13Author: Ali Sheharyar
14Organization: Texas A&M University at Qatar
15*/
16TetrahedralTree::TetrahedralTree(const Vec3& origin, const Vec3& halfDimension)
17 : m_origin(origin), m_halfDimension(halfDimension) {
18 m_min.x = origin.x - halfDimension.x;
19 m_min.y = origin.y - halfDimension.y;
20 m_min.z = origin.z - halfDimension.z;
21 m_max.x = origin.x + halfDimension.x;
22 m_max.y = origin.y + halfDimension.y;
23 m_max.z = origin.z + halfDimension.z;
24
25 // Initially, there are no children
26 for (int i = 0; i < 8; ++i) children[i] = nullptr;
27}
28
30 // Recursively destroy octants
31 for (int i = 0; i < 8; ++i) delete children[i];
32}
33
34// Check if a box overlaps with this node
35bool TetrahedralTree::DoesBoxOverlap(const double bb[6]) const {
36 if (m_max.x < bb[0] || m_max.y < bb[1] || m_max.z < bb[2]) return false;
37 if (m_min.x > bb[3] || m_min.y > bb[4] || m_min.z > bb[5]) return false;
38 return true;
39}
40
41// Determine which octant of the tree would contain 'point'
42int TetrahedralTree::GetOctantContainingPoint(const Vec3& point) const {
43 int oct = 0;
44 if (point.x >= m_origin.x) oct |= 4;
45 if (point.y >= m_origin.y) oct |= 2;
46 if (point.z >= m_origin.z) oct |= 1;
47 return oct;
48}
49
50bool TetrahedralTree::IsLeafNode() const {
51 // We are a leaf if we have no children. Since we either have none, or
52 // all eight, it is sufficient to just check the first.
53 return children[0] == nullptr;
54}
55
56void TetrahedralTree::InsertMeshNode(Vec3 point, const int index) {
57 // Check if it is a leaf node.
58 if (!IsLeafNode()) {
59 // We are at an interior node. Insert recursively into the
60 // appropriate child octant.
61 int octant = GetOctantContainingPoint(point);
62 children[octant]->InsertMeshNode(point, index);
63 return;
64 }
65
66 // Add the new point if the block is not full.
67 if (nodes.size() < BlockCapacity) {
68 nodes.push_back(std::make_pair(point, index));
69 return;
70 }
71 // Block is full, so we need to partition it.
72 // Split the current node and create new empty trees for each child octant.
73 for (int i = 0; i < 8; ++i) {
74 // Compute new bounding box for this child
75 Vec3 newOrigin = m_origin;
76 newOrigin.x += m_halfDimension.x * (i & 4 ? .5f : -.5f);
77 newOrigin.y += m_halfDimension.y * (i & 2 ? .5f : -.5f);
78 newOrigin.z += m_halfDimension.z * (i & 1 ? .5f : -.5f);
79 children[i] = new TetrahedralTree(newOrigin, m_halfDimension * .5f);
80 }
81
82 // Move the mesh nodes from the partitioned node (now marked as interior) to
83 // its children.
84 while (!nodes.empty()) {
85 auto node = nodes.back();
86 nodes.pop_back();
87 const int oct = GetOctantContainingPoint(node.first);
88 children[oct]->InsertMeshNode(node.first, node.second);
89 }
90 // Insert the new point in the appropriate octant.
91 children[GetOctantContainingPoint(point)]->InsertMeshNode(point, index);
92}
93
94void TetrahedralTree::InsertMeshElement(const double bb[6], const int index) {
95 if (IsLeafNode()) {
96 // Add the element to the list of this octant.
97 elements.push_back(index);
98 return;
99 }
100 // Check which children overlap with the element's bounding box.
101 for (int i = 0; i < 8; i++) {
102 if (!children[i]->DoesBoxOverlap(bb)) continue;
103 children[i]->InsertMeshElement(bb, index);
104 }
105}
106
107// It returns the list of tetrahedrons that intersects in a bounding box (Octree
108// block) that contains the
109// point passed as input.
110const std::vector<int>& TetrahedralTree::GetElementsInBlock(const Vec3& point) const {
111 const TetrahedralTree* octreeNode = GetBlockFromPoint(point);
112
113 if (octreeNode) {
114 return octreeNode->elements;
115 }
116
117 return emptyBlock;
118}
119
120// check if the point is inside the domain.
121// This function is only executed at root to ensure that input point is inside
122// the mesh's bounding box
123// If we don't check this, the case when root is leaf node itself will return
124// wrong block
125const TetrahedralTree* TetrahedralTree::GetBlockFromPoint(
126 const Vec3& point) const {
127 if (!(m_min.x <= point.x && point.x <= m_max.x &&
128 m_min.y <= point.y && point.y <= m_max.y &&
129 m_min.z <= point.z && point.z <= m_max.z))
130 return nullptr;
131
132 return GetBlockFromPointHelper(point);
133}
134
135const TetrahedralTree* TetrahedralTree::GetBlockFromPointHelper(
136 const Vec3& point) const {
137 // If we're at a leaf node, it means, the point is inside this block
138 if (IsLeafNode()) return this;
139 // We are at the interior node, so check which child octant contains the
140 // point
141 int octant = GetOctantContainingPoint(point);
142 return children[octant]->GetBlockFromPointHelper(point);
143}
144}
Helper class for searches in field maps.
void InsertMeshElement(const double bb[6], const int index)
Insert a mesh element with given bounding box and index to the tree.
TetrahedralTree(const Vec3 &origin, const Vec3 &halfDimension)
Constructor.
void InsertMeshNode(Vec3 point, const int index)
Insert a mesh node (a vertex/point) to the tree.
const std::vector< int > & GetElementsInBlock(const Vec3 &point) const
Get all elements linked to a block corresponding to the given point.