Я пытаюсь построить дерево квадрантов, которое подразделяет область на основе положения и максимальной глубины. Я хочу использовать это, чтобы реализовать уровень детализации ландшафта. Другими словами, у меня есть позиция (x, y), область (x, y, ширина), и я передаю ее некоторой сборке метода (region, position, maxDepth), которая затем должна возвращать массив узлов, которые покрывают весь самолет.
Моя реализация немного отличается от этой тем, что глубина, а корневая область представлена объектом Quadtree. Чтобы получить общее подразделение, затем вызывается метод-член get (x, y, radius), который затем возвращает массив узлов, покрывающих всю корневую область (проверьте код внизу).
Чтобы избежать появления артефактов, для меня важно, чтобы между соседними узлами был максимум 1 уровень.
Ниже приведен пример приемлемого результата. Самая большая разница между соседними узлами - 1. (диагональные линии можно не учитывать, они просто результат триангуляции)
С другой стороны, это неприемлемо, потому что между тремя соседними узлами существует разница в 2 единицы.
Чтобы исправить это, нам нужно разделить соседние узлы следующим образом:
Другой пример приемлемого решения:
Это код, который у меня есть на данный момент.
class Quadtree {
constructor({ x, y, width }, levels = 6, parent = null) {
this.x = x;
this.y = y;
this.width = width;
this.parent = parent;
this.children = null;
if (levels > 0) {
this.children = this.constructor.split(this, levels); // recursively split quadtree.
}
}
/**
* Checks for intersection.
* @param {x, y, radius} circle
* @param {x, y, width} square
* @return {boolean}
*/
static intersects(circle, square) {
let deltaX = circle.x - Math.max(square.x, Math.min(circle.x, square.x + square.width));
let deltaY = circle.y - Math.max(square.y, Math.min(circle.y, square.y + square.width));
return (deltaX * deltaX + deltaY * deltaY) < (circle.radius * circle.radius);
}
/**
* Splits a node.
*/
static split(node, levels) {
let width = node.width / 2;
let x = node.x;
let y = node.y;
// bottom left
let q1 = new Quadtree({
x: x,
y: y,
width
}, levels - 1, node);
// bottom right
let q2 = new Quadtree({
x: x + width,
y: y,
width
}, levels - 1, node);
// top left
let q3 = new Quadtree({
x: x,
y: y + width,
width
}, levels - 1, node);
// top right
let q4 = new Quadtree({
x: x + width,
y: y + width,
width
}, levels - 1, node);
return [q1, q2, q3, q4];
}
/**
* Gets the least amount of nodes covered by the given circle.
* @param {x, y, radius} circle
* @return {Array} An array of Quadtree-nodes.
*/
get(circle) {
if (this.children !== null && this.constructor.intersects(circle, { x: this.x, y: this.y, width: this.width })) { // we need to go deeper.
return this.children.reduce((arr, child) => {
return arr.concat(child.get(circle));
}, []);
} else {
return [ this ];
}
}
}
Вот пример того, как я бы его использовал:
let tree = new Quadtree({ x: 0, y: 0, width: 100}, 2);
let nodes = tree.get({x: 15, y: 15, radius: 5}); // returns an array of nodes covering the whole region.
Примеры:
tree.get({x: -15, y: -15, radius: 5});
[ Quadtree { x: 0, y: 0, width: 100 } ] // returns the top node.
tree.get({x: 15, y: 15, radius: 5});
[ 7 Quadtree-nodes ]
Последний пример возвращает семь узлов Quadtree следующим образом:
#-------#-------#
| | |
| | |
| | |
#---#---#-------#
| | | |
#---#---| |
| | | |
#---#---#-------#
Если это полезно, узлы Quadtree также хранят указатель на своих родителей.
Я иду в неправильном направлении? Обеспечение ограничений путем возврата вверх по дереву и отслеживания позиций и прочего кажется мне слишком сложным. Есть ли здесь другой ракурс?
2
соседние узлы не находились на расстоянии более2
уровней. - person Anatolii   schedule 05.01.2020