// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // // Author: HoangTRAN, 20/2/2019 #define OCTREE G4Octree #define OCTREE_TEMPLATE typename Iterator, class Extractor,typename Point //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template G4ThreadLocal G4Allocator* OCTREE::fgAllocator = nullptr; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::G4Octree() : functor_(Extractor()) , head_(nullptr) , size_(0) {} //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::G4Octree(Iterator begin, Iterator end) : G4Octree(begin,end,Extractor()) { head_ = nullptr; size_ = 0; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::G4Octree(Iterator begin, Iterator end, Extractor f) : functor_(std::move(f)),head_(nullptr),size_(0) { std::vector> v; for(auto it=begin;it!=end;++it) { v.push_back(std::pair(it,functor_(it))); } size_ = v.size(); head_ = new Node(v); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::G4Octree(OCTREE::tree_type&& rhs) : functor_(rhs.functor_) , head_(rhs.head_) , size_(rhs.size_) {} //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template void OCTREE::swap(OCTREE::tree_type& rhs) { std::swap(head_, rhs.head_); std::swap(functor_, rhs.functor_); std::swap(size_, rhs.size_); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template typename OCTREE::tree_type& OCTREE::operator=(typename OCTREE::tree_type rhs) { swap(rhs); return *this; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template typename OCTREE::tree_type& OCTREE::operator=(typename OCTREE::tree_type&& rhs) { swap(rhs); return *this; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::~G4Octree() { delete head_; } template size_t OCTREE::size() const { return size_; } template OCTREE::Node::Node(const NodeVector& input_values) : Node(input_values, G4DNABoundingBox(InnerIterator(input_values.begin()), InnerIterator(input_values.end())), 0) {} //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::Node::Node( const NodeVector& input_values, const G4DNABoundingBox& box, size_t current_depth): fpValue(nullptr), fBigVolume(box), fNodeType(DEFAULT) { if (current_depth > max_depth) { init_max_depth_leaf(input_values); } else if (input_values.size() <= max_per_node) { init_leaf(input_values); } else { init_internal(input_values, current_depth); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template OCTREE::Node::~Node() { if (fNodeType == NodeTypes::INTERNAL) { childNodeArray& children = *static_cast(fpValue); for (size_t i = 0; i < 8; ++i) { if (children[i] != nullptr) { delete children[i]; children[i] = nullptr; } } delete &children; } else if (fNodeType == NodeTypes::LEAF) { auto toDelete = static_cast(fpValue); toDelete->size_ = 0; delete static_cast(fpValue); } else if (fNodeType == NodeTypes::MAX_DEPTH_LEAF) { delete static_cast(fpValue); } fpValue = nullptr; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template void OCTREE::Node::init_max_depth_leaf( const NodeVector& input_values) { fpValue = new NodeVector(input_values); fNodeType = NodeTypes::MAX_DEPTH_LEAF; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template void OCTREE::Node::init_leaf(const NodeVector& input_values) { std::array, max_per_node> a; std::copy(input_values.begin(), input_values.end(), a.begin()); fpValue = new LeafValues{a, input_values.size()}; fNodeType = NodeTypes::LEAF; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template void OCTREE::Node::init_internal( const NodeVector& input_values, size_t current_depth) { std::array childVectors; std::array boxes = fBigVolume.partition(); std::array children{}; for (size_t child = 0; child < 8; ++child) { NodeVector& childVector = childVectors[child]; childVector.reserve(input_values.size()/8); std::copy_if(input_values.begin(),input_values.end(), std::back_inserter(childVector), [&boxes, child](const std::pair& element) -> G4bool { const Point& p = element.second; return boxes[child].contains(p); } ); children[child] = childVector.empty() ? nullptr : new Node(childVector, boxes[child], ++current_depth); } fpValue = new std::array(children); fNodeType = NodeTypes::INTERNAL; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template template G4bool OCTREE::Node::radiusNeighbors(const Point& query, G4double radius, OutPutContainer& resultIndices) const { G4bool success = false; G4double distance = 0; if (fNodeType == NodeTypes::INTERNAL) { childNodeArray& children = *static_cast(fpValue); for (auto eachChild : children) { if (eachChild == nullptr) { continue; } if(!eachChild->fBigVolume.overlap(query,radius)) { continue; } success = eachChild->radiusNeighbors(query, radius, resultIndices) || success; } } else if (fNodeType == NodeTypes::LEAF) { if(fpValue != nullptr) { LeafValues& children = *static_cast(fpValue); for (size_t i = 0; i < children.size_; ++i) { distance = (query - std::get<1>(children.values_[i])).mag(); if(distance != 0) { if( distance < radius )//TODO: find another solution for this using boundingbox { resultIndices.push_back(std::make_pair(std::get<0>(children.values_[i]),distance)); success = true; } } } } } else if (fNodeType == NodeTypes::MAX_DEPTH_LEAF) { NodeVector& children = *static_cast(fpValue); for (auto & child : children) { const Point& point = std::get<1>(child); //if (this->fBigVolume.contains(query, point, radius)) distance = (query - point).mag(); if( distance == 0. ) { continue; } if( distance < radius ) { if(distance == 0) { throw std::runtime_error("distance == 0 => OCTREE::Node::radiusNeighbors : find itself"); } Iterator resultIndex = std::get<0>(child); resultIndices.push_back(std::make_pair(resultIndex,distance)); success = true; } } } else { throw std::runtime_error("fNodeType is not set : find itself"); } return success; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template template void OCTREE::radiusNeighbors(const Point& query, const G4double& radius, OutPutContainer& resultIndices) const { resultIndices.clear(); if (head_ == nullptr) { return; } head_->radiusNeighbors(query, radius, resultIndices); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... template void* OCTREE::operator new(size_t) { if (!fgAllocator) { fgAllocator = new G4Allocator; } return (void *) fgAllocator->MallocSingle(); } template void OCTREE::operator delete(void *a) { fgAllocator->FreeSingle((OCTREE*)a); }