From 66d6674a299ea475ac448e3489f0ef8b6389e01f Mon Sep 17 00:00:00 2001 From: agargaro Date: Wed, 2 Jul 2025 17:28:19 +0200 Subject: [PATCH 1/6] Add MinHeap for improved performance and replace SortedListPriority --- src/builder/hybridBuilder.ts | 24 +++++++------ src/index.ts | 3 +- src/utils/heap.ts | 64 +++++++++++++++++++++++++++++++++ src/utils/sortedListDesc.ts | 29 --------------- src/utils/sortedListPriority.ts | 26 -------------- 5 files changed, 78 insertions(+), 68 deletions(-) create mode 100644 src/utils/heap.ts delete mode 100644 src/utils/sortedListDesc.ts delete mode 100644 src/utils/sortedListPriority.ts diff --git a/src/builder/hybridBuilder.ts b/src/builder/hybridBuilder.ts index 3eb06e0..efd5624 100644 --- a/src/builder/hybridBuilder.ts +++ b/src/builder/hybridBuilder.ts @@ -1,12 +1,14 @@ import { BVHNode, FloatArray, FloatArrayType } from '../core/BVHNode.js'; import { areaBox, areaFromTwoBoxes, expandBoxByMargin, getLongestAxis, isBoxInsideBox, isExpanded, unionBox, unionBoxChanged } from '../utils/boxUtils.js'; -import { SortedListPriority } from '../utils/sortedListPriority.js'; +import { Heap } from '../utils/heap.js'; import { IBVHBuilder, onLeafCreationCallback } from './IBVHBuilder.js'; +type BVHNodeHeap = { node: BVHNode; inheritedCost: number }; + export class HybridBuilder implements IBVHBuilder { public root: BVHNode = null; public readonly highPrecision: boolean; - protected _sortedList = new SortedListPriority(); + protected _minHeap = new Heap>((a, b) => a.inheritedCost - b.inheritedCost); protected _typeArray: FloatArrayType; protected count = 0; @@ -255,14 +257,14 @@ export class HybridBuilder implements IBVHBuilder { protected findBestSibling(leafBox: FloatArray): BVHNode { const root = this.root; + if (root.object !== undefined) return root; + let bestNode = root; let bestCost = areaFromTwoBoxes(leafBox, root.box); const leafArea = areaBox(leafBox); - if (root.object !== undefined) return root; - - const sortedList = this._sortedList; - sortedList.clear(); + const minHeap = this._minHeap; + minHeap.clear(); let nodeObj = { node: root, inheritedCost: bestCost - areaBox(root.box) }; do { @@ -293,18 +295,18 @@ export class HybridBuilder implements IBVHBuilder { if (inheritedCostR > inheritedCostL) { if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) sortedList.push({ node: nodeL, inheritedCost: inheritedCostL }); + if (nodeL.object === undefined) minHeap.add({ node: nodeL, inheritedCost: inheritedCostL }); if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) sortedList.push({ node: nodeR, inheritedCost: inheritedCostR }); + if (nodeR.object === undefined) minHeap.add({ node: nodeR, inheritedCost: inheritedCostR }); } else { if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) sortedList.push({ node: nodeR, inheritedCost: inheritedCostR }); + if (nodeR.object === undefined) minHeap.add({ node: nodeR, inheritedCost: inheritedCostR }); if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) sortedList.push({ node: nodeL, inheritedCost: inheritedCostL }); + if (nodeL.object === undefined) minHeap.add({ node: nodeL, inheritedCost: inheritedCostL }); } - } while ((nodeObj = sortedList.pop())); + } while ((nodeObj = minHeap.poll())); return bestNode; } diff --git a/src/index.ts b/src/index.ts index e4fe245..86cb89a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,6 @@ export * from './core/BVHNode.js'; export * from './utils/boxUtils.js'; export * from './utils/conversionUtils.js'; export * from './utils/frustum.js'; +export * from './utils/heap.js'; export * from './utils/inspector.js'; export * from './utils/intersectUtils.js'; -export * from './utils/sortedListDesc.js'; -export * from './utils/sortedListPriority.js'; diff --git a/src/utils/heap.ts b/src/utils/heap.ts new file mode 100644 index 0000000..ba12de4 --- /dev/null +++ b/src/utils/heap.ts @@ -0,0 +1,64 @@ +export type Comparator = (a: K, b: K) => number; + +/** + * @reference https://github.com/zrwusa/data-structure-typed/blob/main/src/data-structures/heap/heap.ts + */ +export class Heap { + protected _comparator: Comparator; + protected _elements: E[] = []; + + constructor(comparator: Comparator) { + this._comparator = comparator; + } + + public add(element: E): boolean { + this._elements.push(element); + return this._bubbleUp(this._elements.length - 1); + } + + public poll(): E | undefined { + if (this._elements.length === 0) return; + const value = this._elements[0]; + const last = this._elements.pop(); + if (this._elements.length) { + this._elements[0] = last; + this._sinkDown(0, this._elements.length >> 1); + } + return value; + } + + public clear(): void { + this._elements = []; + } + + protected _bubbleUp(index: number): boolean { + const element = this._elements[index]; + while (index > 0) { + const parent = (index - 1) >> 1; + const parentItem = this._elements[parent]; + if (this._comparator(parentItem, element) <= 0) break; + this._elements[index] = parentItem; + index = parent; + } + this._elements[index] = element; + return true; + } + + protected _sinkDown(index: number, halfLength: number): boolean { + const element = this._elements[index]; + while (index < halfLength) { + let left = (index << 1) | 1; + const right = left + 1; + let minItem = this._elements[left]; + if (right < this._elements.length && this._comparator(minItem, this._elements[right]) > 0) { + left = right; + minItem = this._elements[right]; + } + if (this._comparator(minItem, element) >= 0) break; + this._elements[index] = minItem; + index = left; + } + this._elements[index] = element; + return true; + } +} diff --git a/src/utils/sortedListDesc.ts b/src/utils/sortedListDesc.ts deleted file mode 100644 index 9c23b51..0000000 --- a/src/utils/sortedListDesc.ts +++ /dev/null @@ -1,29 +0,0 @@ -type ItemListType = { node: any; inheritedCost: number }; // fix d.ts - -export class SortedListDesc { - public array: ItemListType[] = []; - - public clear(): void { - this.array.length = 0; - } - - public push(node: ItemListType): void { - const index = this.binarySearch(node.inheritedCost); - this.array.splice(index, 0, node); - } - - public pop(): ItemListType { - return this.array.pop(); - } - - public binarySearch(score: number): number { - const array = this.array; - let low = 0, high = array.length; - while (low < high) { - const mid = (low + high) >>> 1; - if (array[mid].inheritedCost > score) low = mid + 1; - else high = mid; - } - return low; - } -} diff --git a/src/utils/sortedListPriority.ts b/src/utils/sortedListPriority.ts deleted file mode 100644 index 4f3dde3..0000000 --- a/src/utils/sortedListPriority.ts +++ /dev/null @@ -1,26 +0,0 @@ -type ItemListType = { node: any; inheritedCost: number }; // fix d.ts - -export class SortedListPriority { - public array: ItemListType[] = []; - - public clear(): void { - this.array = []; - } - - public push(node: ItemListType): void { - const array = this.array; - const cost = node.inheritedCost; - const end = array.length > 6 ? array.length - 6 : 0; - let i: number; - - for (i = array.length - 1; i >= end; i--) { - if (cost <= array[i].inheritedCost) break; - } - - if (i > array.length - 7) array.splice(i + 1, 0, node); // if in last 6 place, add it do the list - } - - public pop(): ItemListType { - return this.array.pop(); - } -} From 9ad77f28e4492f50ae336cedb05f0d128834980b Mon Sep 17 00:00:00 2001 From: agargaro Date: Thu, 3 Jul 2025 08:43:37 +0200 Subject: [PATCH 2/6] Refactor Heap class methods for improved readability and consistency --- src/utils/heap.ts | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/utils/heap.ts b/src/utils/heap.ts index ba12de4..f320bab 100644 --- a/src/utils/heap.ts +++ b/src/utils/heap.ts @@ -17,48 +17,53 @@ export class Heap { } public poll(): E | undefined { - if (this._elements.length === 0) return; - const value = this._elements[0]; - const last = this._elements.pop(); - if (this._elements.length) { - this._elements[0] = last; - this._sinkDown(0, this._elements.length >> 1); + const elements = this._elements; + if (elements.length === 0) return; + const value = elements[0]; + const last = elements.pop(); + if (elements.length) { + elements[0] = last; + this._sinkDown(0, elements.length >> 1); } return value; } public clear(): void { - this._elements = []; + this._elements.length = 0; } protected _bubbleUp(index: number): boolean { - const element = this._elements[index]; + const comparator = this._comparator; + const elements = this._elements; + const element = elements[index]; while (index > 0) { const parent = (index - 1) >> 1; - const parentItem = this._elements[parent]; - if (this._comparator(parentItem, element) <= 0) break; - this._elements[index] = parentItem; + const parentItem = elements[parent]; + if (comparator(parentItem, element) <= 0) break; + elements[index] = parentItem; index = parent; } - this._elements[index] = element; + elements[index] = element; return true; } protected _sinkDown(index: number, halfLength: number): boolean { - const element = this._elements[index]; + const elements = this._elements; + const element = elements[index]; + const comparator = this._comparator; while (index < halfLength) { let left = (index << 1) | 1; const right = left + 1; - let minItem = this._elements[left]; - if (right < this._elements.length && this._comparator(minItem, this._elements[right]) > 0) { + let minItem = elements[left]; + if (right < elements.length && comparator(minItem, elements[right]) > 0) { left = right; - minItem = this._elements[right]; + minItem = elements[right]; } - if (this._comparator(minItem, element) >= 0) break; - this._elements[index] = minItem; + if (comparator(minItem, element) >= 0) break; + elements[index] = minItem; index = left; } - this._elements[index] = element; + elements[index] = element; return true; } } From 2155289570bb17c98d2dd6bbd59534c0f85ae0ac Mon Sep 17 00:00:00 2001 From: ca-agargaro Date: Fri, 4 Jul 2025 13:05:22 +0200 Subject: [PATCH 3/6] Refactor HybridBuilder to use MinHeap and improve heap item management --- src/builder/hybridBuilder.ts | 22 +++++++++--------- src/utils/heap.ts | 43 ++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/builder/hybridBuilder.ts b/src/builder/hybridBuilder.ts index efd5624..d4edb29 100644 --- a/src/builder/hybridBuilder.ts +++ b/src/builder/hybridBuilder.ts @@ -1,14 +1,12 @@ import { BVHNode, FloatArray, FloatArrayType } from '../core/BVHNode.js'; import { areaBox, areaFromTwoBoxes, expandBoxByMargin, getLongestAxis, isBoxInsideBox, isExpanded, unionBox, unionBoxChanged } from '../utils/boxUtils.js'; -import { Heap } from '../utils/heap.js'; +import { HeapItem, MinHeap } from '../utils/heap.js'; import { IBVHBuilder, onLeafCreationCallback } from './IBVHBuilder.js'; -type BVHNodeHeap = { node: BVHNode; inheritedCost: number }; - export class HybridBuilder implements IBVHBuilder { public root: BVHNode = null; public readonly highPrecision: boolean; - protected _minHeap = new Heap>((a, b) => a.inheritedCost - b.inheritedCost); + protected _minHeap = new MinHeap(); protected _typeArray: FloatArrayType; protected count = 0; @@ -265,10 +263,10 @@ export class HybridBuilder implements IBVHBuilder { const minHeap = this._minHeap; minHeap.clear(); - let nodeObj = { node: root, inheritedCost: bestCost - areaBox(root.box) }; + let nodeObj: HeapItem = { node: root, value: bestCost - areaBox(root.box) }; do { - const { node, inheritedCost } = nodeObj; + const { node, value: inheritedCost } = nodeObj; if (leafArea + inheritedCost >= bestCost) break; @@ -285,26 +283,26 @@ export class HybridBuilder implements IBVHBuilder { if (currentCostL > currentCostR) { if (bestCost > currentCostR) { - bestNode = nodeR; + bestNode = nodeR as BVHNode; bestCost = currentCostR; } } else if (bestCost > currentCostL) { - bestNode = nodeL; + bestNode = nodeL as BVHNode; bestCost = currentCostL; } if (inheritedCostR > inheritedCostL) { if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add({ node: nodeL, inheritedCost: inheritedCostL }); + if (nodeL.object === undefined) minHeap.add(nodeL, inheritedCostL); if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add({ node: nodeR, inheritedCost: inheritedCostR }); + if (nodeR.object === undefined) minHeap.add(nodeR, inheritedCostR); } else { if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add({ node: nodeR, inheritedCost: inheritedCostR }); + if (nodeR.object === undefined) minHeap.add(nodeR, inheritedCostR); if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add({ node: nodeL, inheritedCost: inheritedCostL }); + if (nodeL.object === undefined) minHeap.add(nodeL, inheritedCostL); } } while ((nodeObj = minHeap.poll())); diff --git a/src/utils/heap.ts b/src/utils/heap.ts index f320bab..01aba10 100644 --- a/src/utils/heap.ts +++ b/src/utils/heap.ts @@ -1,22 +1,34 @@ -export type Comparator = (a: K, b: K) => number; +import { BVHNode } from '../core/BVHNode.js'; + +export type HeapItem = { value: number; node: BVHNode }; /** * @reference https://github.com/zrwusa/data-structure-typed/blob/main/src/data-structures/heap/heap.ts */ -export class Heap { - protected _comparator: Comparator; - protected _elements: E[] = []; +export class MinHeap { + protected _elements: HeapItem[] = []; + protected _pool: HeapItem[] = []; + protected _poolIndex: number = 0; - constructor(comparator: Comparator) { - this._comparator = comparator; - } + public add(node: BVHNode, value: number): boolean { + const pool = this._pool; + const elements = this._elements; + const poolIndex = this._poolIndex; + + if (poolIndex >= pool.length) { + pool.push({ value: -1, node: null }); + } + + const item = pool[poolIndex]; + item.node = node; + item.value = value; - public add(element: E): boolean { - this._elements.push(element); - return this._bubbleUp(this._elements.length - 1); + this._poolIndex++; + elements.push(item); + return this._bubbleUp(elements.length - 1); } - public poll(): E | undefined { + public poll(): HeapItem | undefined { const elements = this._elements; if (elements.length === 0) return; const value = elements[0]; @@ -29,17 +41,17 @@ export class Heap { } public clear(): void { + this._poolIndex = 0; this._elements.length = 0; } protected _bubbleUp(index: number): boolean { - const comparator = this._comparator; const elements = this._elements; const element = elements[index]; while (index > 0) { const parent = (index - 1) >> 1; const parentItem = elements[parent]; - if (comparator(parentItem, element) <= 0) break; + if (parentItem.value <= element.value) break; elements[index] = parentItem; index = parent; } @@ -50,16 +62,15 @@ export class Heap { protected _sinkDown(index: number, halfLength: number): boolean { const elements = this._elements; const element = elements[index]; - const comparator = this._comparator; while (index < halfLength) { let left = (index << 1) | 1; const right = left + 1; let minItem = elements[left]; - if (right < elements.length && comparator(minItem, elements[right]) > 0) { + if (right < elements.length && minItem.value > elements[right].value) { left = right; minItem = elements[right]; } - if (comparator(minItem, element) >= 0) break; + if (minItem.value >= element.value) break; elements[index] = minItem; index = left; } From 0ef78bb0695d0cb97bc4d16f4162b37077dbce89 Mon Sep 17 00:00:00 2001 From: agargaro Date: Sat, 5 Jul 2025 10:24:27 +0200 Subject: [PATCH 4/6] Refactor MinHeap to simplify add method and remove unused pool management --- src/builder/hybridBuilder.ts | 8 ++++---- src/utils/heap.ts | 24 ++++-------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/builder/hybridBuilder.ts b/src/builder/hybridBuilder.ts index d4edb29..bdfe2b3 100644 --- a/src/builder/hybridBuilder.ts +++ b/src/builder/hybridBuilder.ts @@ -293,16 +293,16 @@ export class HybridBuilder implements IBVHBuilder { if (inheritedCostR > inheritedCostL) { if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add(nodeL, inheritedCostL); + if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add(nodeR, inheritedCostR); + if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); } else { if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add(nodeR, inheritedCostR); + if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add(nodeL, inheritedCostL); + if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); } } while ((nodeObj = minHeap.poll())); diff --git a/src/utils/heap.ts b/src/utils/heap.ts index 01aba10..e73629a 100644 --- a/src/utils/heap.ts +++ b/src/utils/heap.ts @@ -7,32 +7,17 @@ export type HeapItem = { value: number; node: BVHNode }; */ export class MinHeap { protected _elements: HeapItem[] = []; - protected _pool: HeapItem[] = []; - protected _poolIndex: number = 0; - public add(node: BVHNode, value: number): boolean { - const pool = this._pool; - const elements = this._elements; - const poolIndex = this._poolIndex; - - if (poolIndex >= pool.length) { - pool.push({ value: -1, node: null }); - } - - const item = pool[poolIndex]; - item.node = node; - item.value = value; - - this._poolIndex++; - elements.push(item); - return this._bubbleUp(elements.length - 1); + public add(element: HeapItem): boolean { + this._elements.push(element); + return this._bubbleUp(this._elements.length - 1); } public poll(): HeapItem | undefined { const elements = this._elements; if (elements.length === 0) return; const value = elements[0]; - const last = elements.pop(); + const last = elements.pop()!; if (elements.length) { elements[0] = last; this._sinkDown(0, elements.length >> 1); @@ -41,7 +26,6 @@ export class MinHeap { } public clear(): void { - this._poolIndex = 0; this._elements.length = 0; } From f03933bea04597e7275e895014e1ebc6b8312d26 Mon Sep 17 00:00:00 2001 From: agargaro Date: Sat, 5 Jul 2025 10:26:53 +0200 Subject: [PATCH 5/6] Fix potential null dereference by removing non-null assertion in poll method --- src/utils/heap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/heap.ts b/src/utils/heap.ts index e73629a..97f02cd 100644 --- a/src/utils/heap.ts +++ b/src/utils/heap.ts @@ -17,7 +17,7 @@ export class MinHeap { const elements = this._elements; if (elements.length === 0) return; const value = elements[0]; - const last = elements.pop()!; + const last = elements.pop(); if (elements.length) { elements[0] = last; this._sinkDown(0, elements.length >> 1); From d1617f74b99f48e37e26282edfcb42592b600627 Mon Sep 17 00:00:00 2001 From: agargaro Date: Mon, 7 Jul 2025 15:17:15 +0200 Subject: [PATCH 6/6] Refactor HybridBuilder to remove MinHeap instance and improve findBestSibling method --- src/builder/hybridBuilder.ts | 77 +++++++++++++++++++----------------- src/utils/heap.ts | 5 +++ 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/builder/hybridBuilder.ts b/src/builder/hybridBuilder.ts index bdfe2b3..c4f3588 100644 --- a/src/builder/hybridBuilder.ts +++ b/src/builder/hybridBuilder.ts @@ -6,7 +6,6 @@ import { IBVHBuilder, onLeafCreationCallback } from './IBVHBuilder.js'; export class HybridBuilder implements IBVHBuilder { public root: BVHNode = null; public readonly highPrecision: boolean; - protected _minHeap = new MinHeap(); protected _typeArray: FloatArrayType; protected count = 0; @@ -253,6 +252,7 @@ export class HybridBuilder implements IBVHBuilder { return { parent, left: sibling, right: leaf, box: new this._typeArray(6) } as BVHNode; } + // TODO precalcola area nodo protected findBestSibling(leafBox: FloatArray): BVHNode { const root = this.root; if (root.object !== undefined) return root; @@ -260,51 +260,56 @@ export class HybridBuilder implements IBVHBuilder { let bestNode = root; let bestCost = areaFromTwoBoxes(leafBox, root.box); const leafArea = areaBox(leafBox); + _findBestSibling({ node: root, value: bestCost - areaBox(root.box) }); - const minHeap = this._minHeap; - minHeap.clear(); - let nodeObj: HeapItem = { node: root, value: bestCost - areaBox(root.box) }; + function _findBestSibling(nodeObj: HeapItem): void { + const minHeap = new MinHeap(); - do { - const { node, value: inheritedCost } = nodeObj; + do { + if (minHeap.isFull()) { + _findBestSibling(nodeObj); + } else { + const { node, value: inheritedCost } = nodeObj; - if (leafArea + inheritedCost >= bestCost) break; + if (leafArea + inheritedCost >= bestCost) break; - const nodeL = node.left; - const nodeR = node.right; + const nodeL = node.left; + const nodeR = node.right; - const directCostL = areaFromTwoBoxes(leafBox, nodeL.box); - const currentCostL = directCostL + inheritedCost; - const inheritedCostL = currentCostL - areaBox(nodeL.box); + const directCostL = areaFromTwoBoxes(leafBox, nodeL.box); + const currentCostL = directCostL + inheritedCost; + const inheritedCostL = currentCostL - areaBox(nodeL.box); - const directCostR = areaFromTwoBoxes(leafBox, nodeR.box); - const currentCostR = directCostR + inheritedCost; - const inheritedCostR = currentCostR - areaBox(nodeR.box); + const directCostR = areaFromTwoBoxes(leafBox, nodeR.box); + const currentCostR = directCostR + inheritedCost; + const inheritedCostR = currentCostR - areaBox(nodeR.box); - if (currentCostL > currentCostR) { - if (bestCost > currentCostR) { - bestNode = nodeR as BVHNode; - bestCost = currentCostR; - } - } else if (bestCost > currentCostL) { - bestNode = nodeL as BVHNode; - bestCost = currentCostL; - } + if (currentCostL > currentCostR) { + if (bestCost > currentCostR) { + bestNode = nodeR as BVHNode; + bestCost = currentCostR; + } + } else if (bestCost > currentCostL) { + bestNode = nodeL as BVHNode; + bestCost = currentCostL; + } - if (inheritedCostR > inheritedCostL) { - if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); + if (inheritedCostR > inheritedCostL) { + if (leafArea + inheritedCostL >= bestCost) continue; + if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); - if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); - } else { - if (leafArea + inheritedCostR >= bestCost) continue; - if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); + if (leafArea + inheritedCostR >= bestCost) continue; + if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); + } else { + if (leafArea + inheritedCostR >= bestCost) continue; + if (nodeR.object === undefined) minHeap.add({ node: nodeR, value: inheritedCostR }); - if (leafArea + inheritedCostL >= bestCost) continue; - if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); - } - } while ((nodeObj = minHeap.poll())); + if (leafArea + inheritedCostL >= bestCost) continue; + if (nodeL.object === undefined) minHeap.add({ node: nodeL, value: inheritedCostL }); + } + } + } while ((nodeObj = minHeap.poll())); + } return bestNode; } diff --git a/src/utils/heap.ts b/src/utils/heap.ts index 97f02cd..ac41f63 100644 --- a/src/utils/heap.ts +++ b/src/utils/heap.ts @@ -6,6 +6,7 @@ export type HeapItem = { value: number; node: BVHNode }; * @reference https://github.com/zrwusa/data-structure-typed/blob/main/src/data-structures/heap/heap.ts */ export class MinHeap { + public maxSize = 16; protected _elements: HeapItem[] = []; public add(element: HeapItem): boolean { @@ -25,6 +26,10 @@ export class MinHeap { return value; } + public isFull(): boolean { + return this._elements.length >= this.maxSize; + } + public clear(): void { this._elements.length = 0; }