File indexing completed on 2025-02-23 09:22:01
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include "OctreeNode.hh"
0028
0029 #include "G4VPhysicalVolume.hh"
0030
0031 #include <cassert>
0032 #include <utility>
0033
0034
0035
0036 OctreeNode::OctreeNode(const G4ThreeVector& position, const G4ThreeVector& halfLengths,
0037 G4int maxContents, OctreeNode* parent)
0038 : fPosition(position),
0039 fHalfLengths(halfLengths),
0040 fMaxContents(maxContents),
0041 fParent(parent),
0042 fChildren(std::array<OctreeNode*, 8>())
0043 {
0044 fHalfLengthsMag = fHalfLengths.mag();
0045 }
0046
0047 OctreeNode::~OctreeNode()
0048 {
0049
0050 for (auto& it : fChildren) {
0051 delete it;
0052 }
0053 }
0054
0055
0056
0057 const OctreeNode* OctreeNode::GetChildFromPosition(const G4ThreeVector& pos) const
0058 {
0059 G4ThreeVector localPosition = pos - fPosition;
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 int bit2 = (localPosition.getX() < 0) ? 4 : 0;
0070 int bit1 = (localPosition.getY() < 0) ? 2 : 0;
0071 int bit0 = (localPosition.getZ() < 0) ? 1 : 0;
0072 return fChildren[bit0 + bit1 + bit2];
0073 }
0074
0075
0076
0077
0078 OctreeNode* OctreeNode::GetChildFromPosition(const G4ThreeVector& pos)
0079 {
0080 G4ThreeVector localPosition = pos - fPosition;
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 int bit2 = (localPosition.getX() < 0) ? 4 : 0;
0091 int bit1 = (localPosition.getY() < 0) ? 2 : 0;
0092 int bit0 = (localPosition.getZ() < 0) ? 1 : 0;
0093 int idx = bit0 + bit1 + bit2;
0094
0095 assert(idx < (int)fChildren.size());
0096 return fChildren[idx];
0097 }
0098
0099
0100
0101 void OctreeNode::AddPhysicalVolume(G4VPhysicalVolume* pv)
0102 {
0103
0104 if (this->HasChildren()) {
0105 OctreeNode* child = this->GetChildFromPosition(pv->GetTranslation());
0106 child->AddPhysicalVolume(pv);
0107 }
0108 else {
0109
0110
0111 if ((G4int)fContents.size() == fMaxContents) {
0112 this->Split();
0113 this->AddPhysicalVolume(pv);
0114 }
0115 else {
0116 fContents.push_back(pv);
0117 }
0118 }
0119 }
0120
0121
0122
0123 void OctreeNode::Split()
0124 {
0125 G4ThreeVector hl = 0.5 * fHalfLengths;
0126 G4double xp = fPosition.getX();
0127 G4double yp = fPosition.getY();
0128 G4double zp = fPosition.getZ();
0129 G4double xl = hl.getX();
0130 G4double yl = hl.getY();
0131 G4double zl = hl.getZ();
0132 G4ThreeVector newpos;
0133
0134
0135 newpos = G4ThreeVector(xp + xl, yp + yl, zp + zl);
0136 fChildren[0] = new OctreeNode(newpos, hl, fMaxContents, this);
0137 newpos = G4ThreeVector(xp + xl, yp + yl, zp - zl);
0138 fChildren[1] = new OctreeNode(newpos, hl, fMaxContents, this);
0139 newpos = G4ThreeVector(xp + xl, yp - yl, zp + zl);
0140 fChildren[2] = new OctreeNode(newpos, hl, fMaxContents, this);
0141 newpos = G4ThreeVector(xp + xl, yp - yl, zp - zl);
0142 fChildren[3] = new OctreeNode(newpos, hl, fMaxContents, this);
0143 newpos = G4ThreeVector(xp - xl, yp + yl, zp + zl);
0144 fChildren[4] = new OctreeNode(newpos, hl, fMaxContents, this);
0145 newpos = G4ThreeVector(xp - xl, yp + yl, zp - zl);
0146 fChildren[5] = new OctreeNode(newpos, hl, fMaxContents, this);
0147 newpos = G4ThreeVector(xp - xl, yp - yl, zp + zl);
0148 fChildren[6] = new OctreeNode(newpos, hl, fMaxContents, this);
0149 newpos = G4ThreeVector(xp - xl, yp - yl, zp - zl);
0150 fChildren[7] = new OctreeNode(newpos, hl, fMaxContents, this);
0151
0152
0153
0154 for (int i = fContents.size() - 1; i >= 0; --i) {
0155 G4VPhysicalVolume* pv = fContents[i];
0156 OctreeNode* child = this->GetChildFromPosition(pv->GetTranslation());
0157 assert(child != this);
0158 child->AddPhysicalVolume(pv);
0159 }
0160 fContents.clear();
0161 }
0162
0163
0164
0165 std::vector<G4VPhysicalVolume*> OctreeNode::GetContents() const
0166 {
0167 if (this->HasChildren())
0168 {
0169 std::vector<G4VPhysicalVolume*> vec;
0170 std::vector<G4VPhysicalVolume*> childCont;
0171 for (auto it = fChildren.begin(); it != fChildren.end(); ++it) {
0172 childCont = (*it)->GetContents();
0173 for (auto jt = childCont.begin(); jt != childCont.end(); ++jt) {
0174 vec.push_back(*jt);
0175 }
0176 }
0177 return vec;
0178 }
0179 else
0180 {
0181 return fContents;
0182 }
0183 }
0184
0185
0186
0187
0188 const std::vector<G4VPhysicalVolume*> OctreeNode::SearchOctree(const G4ThreeVector& pos,
0189 G4double _rad) const
0190 {
0191
0192
0193
0194
0195 std::vector<const OctreeNode*> nodes;
0196 std::vector<const OctreeNode*> candidates;
0197 nodes.reserve(512);
0198 candidates.reserve(512);
0199
0200 if (this->HasChildren()) {
0201 for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); it++) {
0202 candidates.push_back(*it);
0203 }
0204 }
0205 else {
0206 candidates.push_back(this);
0207 }
0208
0209 const OctreeNode* aNode;
0210 G4double d;
0211 while (!candidates.empty()) {
0212 aNode = candidates.back();
0213 candidates.pop_back();
0214 d = (aNode->GetPosition() - pos).mag() - aNode->GetHalfLengthsMag();
0215
0216 if (d < _rad) {
0217 if (aNode->HasChildren()) {
0218 for (auto it = aNode->GetChildren().begin(); it != aNode->GetChildren().end(); ++it) {
0219 candidates.push_back(*it);
0220 }
0221 }
0222 else {
0223 nodes.push_back(aNode);
0224 }
0225 }
0226 }
0227
0228
0229
0230
0231 G4double r2 = _rad * _rad;
0232 std::vector<G4VPhysicalVolume*> pvols;
0233 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
0234 std::vector<G4VPhysicalVolume*> conts = (*it)->GetContents();
0235 for (auto jt = conts.begin(); jt != conts.end(); ++jt) {
0236 if ((pos - (*jt)->GetTranslation()).mag2() < r2) {
0237 pvols.push_back((*jt));
0238 }
0239 }
0240 }
0241
0242 return pvols;
0243 }
0244
0245
0246
0247
0248 void OctreeNode::SearchOctree(const G4ThreeVector& pos, std::vector<G4VPhysicalVolume*>& out,
0249 G4double _rad) const
0250 {
0251
0252
0253
0254
0255 std::vector<const OctreeNode*> nodes;
0256 std::vector<const OctreeNode*> candidates;
0257 nodes.reserve(512);
0258 candidates.reserve(512);
0259
0260 if (this->HasChildren()) {
0261 for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); ++it) {
0262 candidates.push_back(*it);
0263 }
0264 }
0265 else {
0266 candidates.push_back(this);
0267 }
0268
0269 const OctreeNode* aNode;
0270 G4double d;
0271 while (!candidates.empty()) {
0272 aNode = candidates.back();
0273 candidates.pop_back();
0274 d = (aNode->GetPosition() - pos).mag() - aNode->GetHalfLengthsMag();
0275
0276 if (d < _rad) {
0277 if (aNode->HasChildren()) {
0278 for (auto it = aNode->GetChildren().begin(); it != aNode->GetChildren().end(); it++) {
0279 candidates.push_back(*it);
0280 }
0281 }
0282 else {
0283 nodes.push_back(aNode);
0284 }
0285 }
0286 }
0287
0288
0289 G4double r2 = _rad * _rad;
0290 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
0291 std::vector<G4VPhysicalVolume*> conts = (*it)->GetContents();
0292 for (auto jt = conts.begin(); jt != conts.end(); ++jt) {
0293 if ((pos - (*jt)->GetTranslation()).mag2() < r2) {
0294 out.push_back((*jt));
0295 }
0296 }
0297 }
0298 }
0299
0300
0301
0302 const std::vector<G4VPhysicalVolume*> OctreeNode::SearchOctree(const G4ThreeVector& pos) const
0303 {
0304 const OctreeNode* child = GetChildFromPosition(pos);
0305 return child->GetContents();
0306 }
0307
0308
0309
0310 G4int OctreeNode::GetNumberOfTerminalNodes()
0311 {
0312 if (!this->HasChildren()) {
0313 return 1;
0314 }
0315
0316 G4int n = 0;
0317 for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); ++it) {
0318 n = n + (*it)->GetNumberOfTerminalNodes();
0319 }
0320
0321 return n;
0322 }
0323