#ifndef FILE_ADTREE #define FILE_ADTREE /* *************************************************************************/ /* File: adtree.hh */ /* Author: Joachim Schoeberl */ /* Date: 16. Feb. 98 */ /* Redesigned by Wolfram Muehlhuber, May 1998 */ /* *************************************************************************/ namespace netgen { /** Alternating Digital Tree */ // #include "../include/mystdlib.h" // #include "../include/myadt.hpp" class ADTreeNode { public: ADTreeNode *left, *right, *father; int dim; float sep; float *data; float *boxmin; float *boxmax; int pi; int nchilds; ADTreeNode (int adim); ~ADTreeNode (); friend class ADTree; }; class ADTreeCriterion { public: ADTreeCriterion() { } virtual int Eval (const ADTreeNode * node) const = 0; }; class ADTree { int dim; ADTreeNode * root; float *cmin, *cmax; NgArray ela; const ADTreeCriterion * criterion; NgArray stack; NgArray stackdir; int stackindex; public: ADTree (int adim, const float * acmin, const float * acmax); ~ADTree (); void Insert (const float * p, int pi); // void GetIntersecting (const float * bmin, const float * bmax, // NgArray & pis) const; void SetCriterion (ADTreeCriterion & acriterion); void Reset (); int Next (); void GetMatch (NgArray & matches); void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode * node) const; }; class ADTreeNode3 { public: ADTreeNode3 *left, *right, *father; float sep; float data[3]; int pi; int nchilds; ADTreeNode3 (); void DeleteChilds (); friend class ADTree3; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; class ADTree3 { ADTreeNode3 * root; float cmin[3], cmax[3]; NgArray ela; public: ADTree3 (const float * acmin, const float * acmax); ~ADTree3 (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode3 * node) const; }; /* // divide each direction #define ADTN_DIV 10 class ADTreeNode3Div { public: ADTreeNode3Div *father; ADTreeNode3Div *childs[ADTN_DIV]; float minx, dist; float data[3]; int pi; int nchilds; ADTreeNode3Div (); void DeleteChilds (); friend class ADTree3Div; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; class ADTree3Div { ADTreeNode3Div * root; float cmin[3], cmax[3]; NgArray ela; public: ADTree3Div (const float * acmin, const float * acmax); ~ADTree3Div (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode3Div * node) const; }; #define ADTN_SIZE 10 // multiple entries class ADTreeNode3M { public: ADTreeNode3M *left, *right, *father; float sep; float data[ADTN_SIZE][3]; int pi[ADTN_SIZE]; int nchilds; ADTreeNode3M (); void DeleteChilds (); friend class ADTree3M; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; class ADTree3M { ADTreeNode3M * root; float cmin[3], cmax[3]; NgArray ela; public: ADTree3M (const float * acmin, const float * acmax); ~ADTree3M (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode3M * node) const; }; class ADTreeNode3F { public: ADTreeNode3F *father; ADTreeNode3F *childs[8]; float sep[3]; float data[3]; int pi; int nchilds; ADTreeNode3F (); void DeleteChilds (); friend class ADTree3F; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; // fat tree class ADTree3F { ADTreeNode3F * root; float cmin[3], cmax[3]; NgArray ela; public: ADTree3F (const float * acmin, const float * acmax); ~ADTree3F (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode3F * node) const; }; class ADTreeNode3FM { public: ADTreeNode3FM *father; ADTreeNode3FM *childs[8]; float sep[3]; float data[ADTN_SIZE][3]; int pi[ADTN_SIZE]; int nchilds; ADTreeNode3FM (); void DeleteChilds (); friend class ADTree3FM; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; // fat tree class ADTree3FM { ADTreeNode3FM * root; float cmin[3], cmax[3]; NgArray ela; public: ADTree3FM (const float * acmin, const float * acmax); ~ADTree3FM (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } void PrintRec (ostream & ost, const ADTreeNode3FM * node) const; }; */ class ADTreeNode6 { public: ADTreeNode6 *left, *right, *father; float sep; float data[6]; int pi; int nchilds; ADTreeNode6 (); void DeleteChilds (); friend class ADTree6; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; class ADTree6 { ADTreeNode6 * root; float cmin[6], cmax[6]; NgArray ela; public: ADTree6 (const float * acmin, const float * acmax); ~ADTree6 (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } int Depth () const { return DepthRec (root); } int Elements () const { return ElementsRec (root); } void PrintRec (ostream & ost, const ADTreeNode6 * node) const; int DepthRec (const ADTreeNode6 * node) const; int ElementsRec (const ADTreeNode6 * node) const; void PrintMemInfo (ostream & ost) const; }; template class T_ADTreeNode { public: T_ADTreeNode *left, *right, *father; float sep; // float data[DIM]; Point data; T pi; int nchilds; T_ADTreeNode () { // pi = -1; SetInvalid(pi); left = NULL; right = NULL; father = NULL; nchilds = 0; } void DeleteChilds (BlockAllocator & ball) { if (left) { left->DeleteChilds(ball); ball.Free(left); left = NULL; } if (right) { right->DeleteChilds(ball); ball.Free(right); right = NULL; } } }; template class T_ADTree { T_ADTreeNode * root; // float cmin[dim], cmax[dim]; Point cmin, cmax; // NgArray*> ela; ClosedHashTable*> ela; BlockAllocator ball{sizeof(T_ADTreeNode)}; public: T_ADTree (Point acmin, Point acmax) { cmin = acmin; cmax = acmax; root = new (ball.Alloc()) T_ADTreeNode; root->sep = (cmin[0] + cmax[0]) / 2; } ~T_ADTree () { root->DeleteChilds(ball); ball.Free(root); } void Insert (Point p, T pi) { T_ADTreeNode *node(NULL); T_ADTreeNode *next; int dir; int lr(0); Point bmin = cmin; Point bmax = cmax; next = root; dir = 0; while (next) { node = next; if (IsInvalid(node->pi)) { // memcpy (node->data, p, dim * sizeof(float)); node->data = p; node->pi = pi; // if (ela.Size() < pi+1) // ela.SetSize (pi+1); ela[pi] = node; return; } if (node->sep > p[dir]) { next = node->left; bmax(dir) = node->sep; lr = 0; } else { next = node->right; bmin(dir) = node->sep; lr = 1; } dir++; if (dir == dim) dir = 0; } next = new (ball.Alloc()) T_ADTreeNode; next->data = p; next->pi = pi; next->sep = (bmin[dir] + bmax[dir]) / 2; // if (ela.Size() < pi+1) // ela.SetSize (pi+1); ela[pi] = next; if (lr) node->right = next; else node->left = next; next -> father = node; while (node) { node->nchilds++; node = node->father; } } class inttn { public: int dir; T_ADTreeNode * node; }; void GetIntersecting (Point bmin, Point bmax, NgArray & pis) const { NgArrayMem stack(10000); pis.SetSize(0); stack[0].node = root; stack[0].dir = 0; int stacks = 0; while (stacks >= 0) { T_ADTreeNode * node = stack[stacks].node; int dir = stack[stacks].dir; stacks--; if (!IsInvalid(node->pi)) // != -1) { bool found = true; for (int i = 0; i < dim/2; i++) if (node->data[i] > bmax[i]) found = false; for (int i = dim/2; i < dim; i++) if (node->data[i] < bmin[i]) found = false; if (found) pis.Append (node->pi); /* if (node->data[0] > bmax[0] || node->data[1] > bmax[1] || node->data[2] > bmax[2] || node->data[3] < bmin[3] || node->data[4] < bmin[4] || node->data[5] < bmin[5]) ; else { pis.Append (node->pi); } */ } int ndir = (dir+1) % dim; if (node->left && bmin[dir] <= node->sep) { stacks++; stack[stacks].node = node->left; stack[stacks].dir = ndir; } if (node->right && bmax[dir] >= node->sep) { stacks++; stack[stacks].node = node->right; stack[stacks].dir = ndir; } } } void DeleteElement (T pi) { T_ADTreeNode * node = ela[pi]; ela.Delete(pi); SetInvalid(node->pi); // = -1; node = node->father; while (node) { node->nchilds--; node = node->father; } } void Print (ostream & ost) const { PrintRec (ost, root); } int Depth () const { return DepthRec (root); } int Elements () const { return ElementsRec (root); } void PrintRec (ostream & ost, const T_ADTreeNode * node) const { // if (node->data) // true anyway { ost << node->pi << ": "; ost << node->nchilds << " childs, "; for (int i = 0; i < dim; i++) ost << node->data[i] << " "; ost << endl; } if (node->left) PrintRec (ost, node->left); if (node->right) PrintRec (ost, node->right); } int DepthRec (const T_ADTreeNode * node) const { int ldepth = 0; int rdepth = 0; if (node->left) ldepth = DepthRec(node->left); if (node->right) rdepth = DepthRec(node->right); return 1 + max2 (ldepth, rdepth); } int ElementsRec (const T_ADTreeNode * node) const { int els = 1; if (node->left) els += ElementsRec(node->left); if (node->right) els += ElementsRec(node->right); return els; } void PrintMemInfo (ostream & ost) const { ost << Elements() << " elements a " << sizeof(ADTreeNode6) << " Bytes = " << Elements() * sizeof(T_ADTreeNode) << endl; ost << "maxind = " << ela.Size() << " = " << sizeof(T_ADTreeNode*) * ela.Size() << " Bytes" << endl; } }; /* class ADTreeNode6F { public: ADTreeNode6F * father; ADTreeNode6F * childs[64]; float sep[6]; float data[6]; int pi; int nchilds; ADTreeNode6F (); void DeleteChilds (); friend class ADTree6F; static BlockAllocator ball; void * operator new(size_t); void operator delete (void *); }; class ADTree6F { ADTreeNode6F * root; float cmin[6], cmax[6]; NgArray ela; public: ADTree6F (const float * acmin, const float * acmax); ~ADTree6F (); void Insert (const float * p, int pi); void GetIntersecting (const float * bmin, const float * bmax, NgArray & pis) const; void DeleteElement (int pi); void Print (ostream & ost) const { PrintRec (ost, root); } int Depth () const { return DepthRec (root); } void PrintRec (ostream & ost, const ADTreeNode6F * node) const; int DepthRec (const ADTreeNode6F * node) const; }; */ class Point3dTree { ADTree3 * tree; public: DLL_HEADER Point3dTree (const Point<3> & pmin, const Point<3> & pmax); DLL_HEADER ~Point3dTree (); DLL_HEADER void Insert (const Point<3> & p, int pi); void DeleteElement (int pi) { tree->DeleteElement(pi); } DLL_HEADER void GetIntersecting (const Point<3> & pmin, const Point<3> & pmax, NgArray & pis) const; const ADTree3 & Tree() const { return *tree; }; }; template class BoxTree { public: // Number of entries per leaf static constexpr int N = 100; struct Node; struct Leaf { Point<2*dim> p[N]; T index[N]; int n_elements; Leaf() : n_elements(0) { } void Add( ClosedHashTable &leaf_index, const Point<2*dim> &ap, T aindex ) { p[n_elements] = ap; index[n_elements] = aindex; n_elements++; leaf_index[aindex] = this; } }; struct Node { union { Node *children[2]; Leaf *leaf; }; double sep; int level; Node() : children{nullptr,nullptr} { } ~Node() { } Leaf *GetLeaf() const { return children[1] ? nullptr : leaf; } }; private: Node root; ClosedHashTable leaf_index; Point global_min, global_max; double tol; size_t n_leaves; size_t n_nodes; BlockAllocator ball_nodes; BlockAllocator ball_leaves; public: BoxTree (const Point & pmin, const Point & pmax) : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) { root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); root.level = 0; tol = 1e-7 * Dist(pmax, pmin); } BoxTree (const Box & box) : BoxTree(box.PMin(), box.PMax()) { } double GetTolerance() { return tol; } size_t GetNLeaves() { return n_leaves; } size_t GetNNodes() { return n_nodes; } template void GetFirstIntersecting (const Point & pmin, const Point & pmax, TFunc func=[](auto pi){return false;}) const { // static Timer timer("BoxTree::GetIntersecting"); RegionTimer rt(timer); // static Timer timer1("BoxTree::GetIntersecting-LinearSearch"); ArrayMem stack; ArrayMem dir_stack; Point<2*dim> tpmin, tpmax; for (size_t i : IntRange(dim)) { tpmin(i) = global_min(i); tpmax(i) = pmax(i)+tol; tpmin(i+dim) = pmin(i)-tol; tpmax(i+dim) = global_max(i); } stack.SetSize(0); stack.Append(&root); dir_stack.SetSize(0); dir_stack.Append(0); while(stack.Size()) { const Node *node = stack.Last(); stack.DeleteLast(); int dir = dir_stack.Last(); dir_stack.DeleteLast(); if(Leaf *leaf = node->GetLeaf()) { // RegionTimer rt1(timer1); for (auto i : IntRange(leaf->n_elements)) { bool intersect = true; const auto p = leaf->p[i]; for (int d = 0; d < dim; d++) if (p[d] > tpmax[d]) intersect = false; for (int d = dim; d < 2*dim; d++) if (p[d] < tpmin[d]) intersect = false; if(intersect) if(func(leaf->index[i])) return; } } else { int newdir = dir+1; if(newdir==2*dim) newdir = 0; if (tpmin[dir] <= node->sep) { stack.Append(node->children[0]); dir_stack.Append(newdir); } if (tpmax[dir] >= node->sep) { stack.Append(node->children[1]); dir_stack.Append(newdir); } } } } void GetIntersecting (const Point & pmin, const Point & pmax, NgArray & pis) const { pis.SetSize(0); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void GetIntersecting(const Point & pmin, const Point & pmax, Array & pis) const { pis.SetSize0(); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void Insert (const Box & box, T pi) { Insert (box.PMin(), box.PMax(), pi); } void Insert (const Point & pmin, const Point & pmax, T pi) { // static Timer timer("BoxTree::Insert"); RegionTimer rt(timer); int dir = 0; Point<2*dim> p; for (auto i : IntRange(dim)) { p(i) = pmin[i]; p(i+dim) = pmax[i]; } Node * node = &root; Leaf * leaf = node->GetLeaf(); // search correct leaf to add point while(!leaf) { node = p[dir] < node->sep ? node->children[0] : node->children[1]; dir++; if(dir==2*dim) dir = 0; leaf = node->GetLeaf(); } // add point to leaf if(leaf->n_elements < N) leaf->Add(leaf_index, p,pi); else // assume leaf->n_elements == N { // add two new nodes and one new leaf int n_elements = leaf->n_elements; ArrayMem coords(n_elements); ArrayMem order(n_elements); // separate points in two halves, first sort all coordinates in direction dir for (auto i : IntRange(n_elements)) { order[i] = i; coords[i] = leaf->p[i][dir]; } QuickSortI(coords, order); int isplit = N/2; Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); for (auto i : order.Range(isplit)) leaf1->Add(leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaf_index, leaf->p[i], leaf->index[i] ); Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); node1->leaf = leaf1; node1->level = node->level+1; Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); node2->leaf = leaf2; node2->level = node->level+1; node->children[0] = node1; node->children[1] = node2; node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); // add new point to one of the new leaves if (p[dir] < node->sep) leaf1->Add( leaf_index, p, pi ); else leaf2->Add( leaf_index, p, pi ); ball_leaves.Free(leaf); n_leaves++; n_nodes+=2; } } void DeleteElement (T pi) { // static Timer timer("BoxTree::DeleteElement"); RegionTimer rt(timer); Leaf *leaf = leaf_index[pi]; leaf_index.Delete(pi); auto & n_elements = leaf->n_elements; auto & index = leaf->index; auto & p = leaf->p; for (auto i : IntRange(n_elements)) { if(index[i] == pi) { n_elements--; if(i!=n_elements) { index[i] = index[n_elements]; p[i] = p[n_elements]; } return; } } } }; // template // class BoxTree // { // T_ADTree<2*dim,T> * tree; // Point boxpmin, boxpmax; // public: // BoxTree (const Box & abox) // { // boxpmin = abox.PMin(); // boxpmax = abox.PMax(); // Point<2*dim> tpmin, tpmax; // for (int i = 0; i < dim; i++) // { // tpmin(i) = tpmin(i+dim) = boxpmin(i); // tpmax(i) = tpmax(i+dim) = boxpmax(i); // } // tree = new T_ADTree<2*dim,T> (tpmin, tpmax); // } // // BoxTree (const Point & apmin, const Point & apmax) // { // boxpmin = apmin; // boxpmax = apmax; // Point<2*dim> tpmin, tpmax; // for (int i = 0; i < dim; i++) // { // tpmin(i) = tpmin(i+dim) = boxpmin(i); // tpmax(i) = tpmax(i+dim) = boxpmax(i); // } // tree = new T_ADTree<2*dim,T> (tpmin, tpmax); // } // // ~BoxTree () // { // delete tree; // } // // void Insert (const Point & bmin, const Point & bmax, T pi) // { // Point<2*dim> tp; // // for (size_t i = 0; i < dim; i++) // { // tp(i) = bmin(i); // tp(i+dim) = bmax(i); // } // // tree->Insert (tp, pi); // } // // void Insert (const Box & box, T pi) // { // Insert (box.PMin(), box.PMax(), pi); // } // // void DeleteElement (T pi) // { // tree->DeleteElement(pi); // } // // void GetIntersecting (const Point & pmin, const Point & pmax, // NgArray & pis) const // { // Point<2*dim> tpmin, tpmax; // double tol = Tolerance(); // for (size_t i = 0; i < dim; i++) // { // tpmin(i) = boxpmin(i); // tpmax(i) = pmax(i)+tol; // // tpmin(i+dim) = pmin(i)-tol; // tpmax(i+dim) = boxpmax(i); // } // // tree->GetIntersecting (tpmin, tpmax, pis); // } // // // double Tolerance() const { return 1e-7 * Dist(boxpmax, boxpmin); } // single precision // const auto & Tree() const { return *tree; }; // auto & Tree() { return *tree; }; // }; template class DelaunayTree { public: // Number of entries per leaf static constexpr int N = 100; struct Node; struct Leaf { Point<2*dim, TSCAL> p[N]; T index[N]; int n_elements; int nr; Leaf() : n_elements(0) { } void Add( Array &leaves, Array &leaf_index, const Point<2*dim> &ap, T aindex ) { p[n_elements] = ap; index[n_elements] = aindex; n_elements++; if(leaf_index.Size() leaves; Array leaf_index; Point global_min, global_max; double tol; size_t n_leaves; size_t n_nodes; BlockAllocator ball_nodes; BlockAllocator ball_leaves; public: DelaunayTree (const Point & pmin, const Point & pmax) : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) { root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); root.leaf->nr = 0; leaves.Append(root.leaf); root.level = 0; tol = 1e-7 * Dist(pmax, pmin); } DelaunayTree (const Box & box) : DelaunayTree(box.PMin(), box.PMax()) { } size_t GetNLeaves() { return n_leaves; } size_t GetNNodes() { return n_nodes; } template void GetFirstIntersecting (const Point & pmin, const Point & pmax, TFunc func=[](auto pi){return false;}) const { // static Timer timer("DelaunayTree::GetIntersecting"); RegionTimer rt(timer); // static Timer timer1("DelaunayTree::GetIntersecting-LinearSearch"); ArrayMem stack; ArrayMem dir_stack; Point<2*dim> tpmin, tpmax; for (size_t i : IntRange(dim)) { tpmin(i) = global_min(i); tpmax(i) = pmax(i)+tol; tpmin(i+dim) = pmin(i)-tol; tpmax(i+dim) = global_max(i); } stack.SetSize(0); stack.Append(&root); dir_stack.SetSize(0); dir_stack.Append(0); while(stack.Size()) { const Node *node = stack.Last(); stack.DeleteLast(); int dir = dir_stack.Last(); dir_stack.DeleteLast(); if(Leaf *leaf = node->GetLeaf()) { // RegionTimer rt1(timer1); for (auto i : IntRange(leaf->n_elements)) { bool intersect = true; const auto p = leaf->p[i]; for (int d = 0; d < dim; d++) if (p[d] > tpmax[d]) intersect = false; for (int d = dim; d < 2*dim; d++) if (p[d] < tpmin[d]) intersect = false; if(intersect) if(func(leaf->index[i])) return; } } else { int newdir = dir+1; if(newdir==2*dim) newdir = 0; if (tpmin[dir] <= node->sep) { stack.Append(node->children[0]); dir_stack.Append(newdir); } if (tpmax[dir] >= node->sep) { stack.Append(node->children[1]); dir_stack.Append(newdir); } } } } void GetIntersecting (const Point & pmin, const Point & pmax, NgArray & pis) const { pis.SetSize(0); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void Insert (const Box & box, T pi) { Insert (box.PMin(), box.PMax(), pi); } void Insert (const Point & pmin, const Point & pmax, T pi) { // static Timer timer("DelaunayTree::Insert"); RegionTimer rt(timer); int dir = 0; Point<2*dim> p; for (auto i : IntRange(dim)) { p(i) = pmin[i]; p(i+dim) = pmax[i]; } Node * node = &root; Leaf * leaf = node->GetLeaf(); // search correct leaf to add point while(!leaf) { node = p[dir] < node->sep ? node->children[0] : node->children[1]; dir++; if(dir==2*dim) dir = 0; leaf = node->GetLeaf(); } // add point to leaf if(leaf->n_elements < N) leaf->Add(leaves, leaf_index, p,pi); else // assume leaf->n_elements == N { // add two new nodes and one new leaf int n_elements = leaf->n_elements; ArrayMem coords(n_elements); ArrayMem order(n_elements); // separate points in two halves, first sort all coordinates in direction dir for (auto i : IntRange(n_elements)) { order[i] = i; coords[i] = leaf->p[i][dir]; } QuickSortI(coords, order); int isplit = N/2; Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); leaf1->nr = leaf->nr; leaf2->nr = leaves.Size(); leaves.Append(leaf2); leaves[leaf1->nr] = leaf1; for (auto i : order.Range(isplit)) leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); node1->leaf = leaf1; node1->level = node->level+1; Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); node2->leaf = leaf2; node2->level = node->level+1; node->children[0] = node1; node->children[1] = node2; node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); // add new point to one of the new leaves if (p[dir] < node->sep) leaf1->Add( leaves, leaf_index, p, pi ); else leaf2->Add( leaves, leaf_index, p, pi ); ball_leaves.Free(leaf); n_leaves++; n_nodes+=2; } } void DeleteElement (T pi) { // static Timer timer("DelaunayTree::DeleteElement"); RegionTimer rt(timer); Leaf *leaf = leaves[leaf_index[pi]]; leaf_index[pi] = -1; auto & n_elements = leaf->n_elements; auto & index = leaf->index; auto & p = leaf->p; for (auto i : IntRange(n_elements)) { if(index[i] == pi) { n_elements--; if(i!=n_elements) { index[i] = index[n_elements]; p[i] = p[n_elements]; } return; } } } }; } #endif