【发布时间】:2020-11-07 08:29:34
【问题描述】:
我有一个伪四叉树算法,它按到当前鼠标位置的距离来划分空间。
为什么是伪的?它不会创建每个节点有 4 个子节点或没有子节点的正确树(如果它是终端节点)。取而代之的是,该算法以顺时针顺序将分区替换为其四个子级。
我需要轻松获取每个分区的邻居,并且非常确定我需要为所有节点创建和更新邻接矩阵。很确定它必须在 Quadtree.splitNode() 函数中。
到现在为止,我还没有任何想法如何制作自己。
我附上了带有交互式画布和表格的片段,应该使用邻接矩阵进行更新。
var mouse = {x: 0, y: 0}, colors = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000'];
class Node{
constructor(level_, index_, centerX_, centerY_, width_, height_, resolution_){
this.level = level_;
this.index = index_;
this.w = width_;
this.h = height_;
this.x = centerX_;
this.y = centerY_;
this.resolution = resolution_;
this.edges = this.getEdges();
}
getEdges = function(){
return [
{x: this.x - this.w / 2, y: this.y - this.h / 2},
{x: this.x + this.w / 2, y: this.y - this.h / 2},
{x: this.x + this.w / 2, y: this.y + this.h / 2},
{x: this.x - this.w / 2, y: this.y + this.h / 2}
];
}
getAdjacency = function(){
return [
{x: this.x - this.w / 2, y: this.y - this.h / 2},
{x: this.x + this.w / 2, y: this.y - this.h / 2},
{x: this.x + this.w / 2, y: this.y + this.h / 2},
{x: this.x - this.w / 2, y: this.y + this.h / 2}
];
}
}
class Quadtree{
constructor(root_, levels_, distance_){
var this_ = this;
this.levels = levels_;
this.distance = distance_;
this.root = root_;
this.nodes = [];
this.nodes = this.splitNode(0, this.root, false);
this.generateLevels();
this.last = [...this.nodes];
this.tiles = {};
this.debug = {};
this.points = [];
this.adjacency = [
["-", 0, 1, 2, 3],
[0, 0, 1, 0, 1 ],
[1, 1, 0, 1, 0],
[2, 0, 1, 0, 1],
[3, 1, 0, 1, 0]
];
}
generateLevels = function(){
for(var i = 0; i < this.levels; i++){
var tmpNodes = [];
for(var j = 0; j < this.nodes.length; j++){
tmpNodes.push(...this.splitNode(j, this.nodes[j], true));
}
this.nodes = tmpNodes;
}
}
update = function(){
var this_ = this;
this.nodes = [];
this.nodes = this.splitNode(0, this.root, false);
this.generateLevels();
this.debug = {};
this.last = [...this.nodes];
}
splitNode = function(index_, parent_, check_){
if((parent_.level < this.levels && this.sqrtDistance(parent_) < this.distance) || !check_){
var lt = new Node(parent_.level + 1, { x: parent_.index.x * 2, y: parent_.index.y * 2 }, parent_.x - parent_.w / 4, parent_.y - parent_.h / 4, parent_.w / 2, parent_.h / 2, parent_.resolution / 2);
var rt = new Node(parent_.level + 1, { x: parent_.index.x * 2, y: parent_.index.y * 2 + 1 }, parent_.x + parent_.w / 4, parent_.y - parent_.h / 4, parent_.w / 2, parent_.h / 2, parent_.resolution / 2);
var rb = new Node(parent_.level + 1, { x: parent_.index.x * 2 + 1, y: parent_.index.y * 2 + 1 }, parent_.x + parent_.w / 4, parent_.y + parent_.h / 4, parent_.w / 2, parent_.h / 2, parent_.resolution / 2);
var lb = new Node(parent_.level + 1, { x: parent_.index.x * 2 + 1, y: parent_.index.y * 2 }, parent_.x - parent_.w / 4, parent_.y + parent_.h / 4, parent_.w / 2, parent_.h / 2, parent_.resolution / 2);
return [lt, rt, rb, lb];
}
return [parent_];
}
sqrtDistance = function(node_){
var target = mouse;
var x1 = node_.x - node_.w / 2.0;
var y1 = node_.y - node_.h / 2.0;
var x2 = node_.x + node_.w / 2.0;
var y2 = node_.y + node_.h / 2.0;
var rx = (x1 + x2) / 2.0;
var ry = (y1 + y2) / 2.0;
var rwidth = node_.w;
var rheight = node_.h;
var dx = Math.max(Math.abs(target.x - rx) - rwidth / 2, 0);
var dy = Math.max(Math.abs(target.y - ry) - rheight / 2, 0);
return Math.sqrt(dx * dx + dy * dy);
}
}
var root = new Node(0, {x: 0, y: 0}, 512, 512, 992, 992, 1);
var quad = new Quadtree(root, 5, 16.0);
quad.update();
var canvas = document.getElementById("quad");
var ctx = canvas.getContext("2d");
generateAdjacencyTable();
function drawQuad(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
quad.nodes.forEach(function(node_, i_){
//contours
var points = node_.getEdges();
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for(var i = 1; i < points.length; i++){ ctx.lineTo(points[i].x, points[i].y); }
ctx.lineTo(points[0].x, points[0].y);
//ctx.strokeStyle = colors[i_ % 20];
ctx.stroke();
})
}
function generateAdjacencyTable(){
if(document.getElementById("adjTable") != undefined){
var oldTbl = document.getElementById("adjTable");
oldTbl.parentNode.removeChild(oldTbl);
}
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
tbl.style = "margin: 8px;";
tbl.id = "adjTable";
var tblBody = document.createElement("tbody");
for(var j = 0; j < quad.adjacency.length; j++) {
var row = document.createElement("tr");
for(var i = 0; i < quad.adjacency[j].length; i++) {
var cell = document.createElement("td");
var cellText = document.createTextNode(quad.adjacency[i][j]);
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "1");
}
document.addEventListener("mousemove", onMouseMoveEvent, false);
function onMouseMoveEvent(event_){
var rect = canvas.getBoundingClientRect();
mouse = {
x: (event_.clientX - rect.left) * 2,
y: (event_.clientY - rect.top) * 2
};
quad.update();
drawQuad();
}
body { margin: 0; }
tbody td:first-child, tr:first-child { background: rgb(192, 192, 192); }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="quad" width="1024" height="1024" style="width: 512px; height: 512px;"></canvas>
</body>
</html>
【问题讨论】:
标签: javascript adjacency-matrix quadtree neighbours