mirror of
https://github.com/penpot/penpot.git
synced 2025-06-10 12:21:39 +02:00
Move all files under frontend directory.
This commit is contained in:
parent
92b45b2d05
commit
e21798f1ed
603 changed files with 10 additions and 31 deletions
225
frontend/src/uxbox/util/kdtree_impl.js
Normal file
225
frontend/src/uxbox/util/kdtree_impl.js
Normal file
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* kdtree
|
||||
*
|
||||
* Is a modified and google closure adapted kdtree implementation
|
||||
* of https://github.com/ubilabs/kd-tree-javascript.
|
||||
*
|
||||
* @author Andrey Antukh <niwi@niwi.nz>, 2016
|
||||
* @author Mircea Pricop <pricop@ubilabs.net>, 2012
|
||||
* @author Martin Kleppe <kleppe@ubilabs.net>, 2012
|
||||
* @author Ubilabs http://ubilabs.net, 2012
|
||||
* @license MIT License <https://opensource.org/licenses/MIT>
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
goog.provide("uxbox.util.kdtree_impl");
|
||||
goog.require("uxbox.util.heap_impl");
|
||||
goog.require("uxbox.util.lru_impl");
|
||||
goog.require("goog.asserts");
|
||||
|
||||
goog.scope(function() {
|
||||
const self = uxbox.util.kdtree_impl;
|
||||
|
||||
const heap = uxbox.util.heap_impl;
|
||||
const lru = uxbox.util.lru_impl;
|
||||
const assert = goog.asserts.assert;
|
||||
|
||||
// Hardcoded dimensions value;
|
||||
const dimensions = 2;
|
||||
|
||||
class Node {
|
||||
constructor(obj, dimension, parent) {
|
||||
this.obj = obj;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
this.parent = parent;
|
||||
this.dimension = dimension;
|
||||
}
|
||||
}
|
||||
|
||||
class KDTree {
|
||||
constructor() {
|
||||
this.root = null;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Private Api (implementation)
|
||||
|
||||
function precision(v) {
|
||||
return parseFloat(v.toFixed(6));
|
||||
}
|
||||
|
||||
function calculateDistance(a, b){
|
||||
return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2));
|
||||
}
|
||||
|
||||
function buildTree(parent, points, depth) {
|
||||
const dim = depth % dimensions;
|
||||
|
||||
if (points.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (points.length === 1) {
|
||||
return new Node(points[0], dim, parent);
|
||||
}
|
||||
|
||||
points.sort((a, b) => {
|
||||
return a[dim] - b[dim];
|
||||
});
|
||||
|
||||
const median = Math.floor(points.length / 2);
|
||||
const node = new Node(points[median], dim, parent);
|
||||
node.left = buildTree(node, points.slice(0, median), depth + 1);
|
||||
node.right = buildTree(node, points.slice(median + 1), depth + 1);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function searchNearest(root, point, maxNodes) {
|
||||
const search = (best, node) => {
|
||||
if (best === null) {
|
||||
best = new heap.MinHeap((x, y) => x[1] - y[1]);
|
||||
}
|
||||
|
||||
let distance = precision(calculateDistance(point, node.obj));
|
||||
|
||||
if (best.isEmpty()) {
|
||||
best.insert([node.obj, distance]);
|
||||
} else {
|
||||
if (distance < best.peek()[1]) {
|
||||
best.insert([node.obj, distance]);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.right === null && node.left === null) {
|
||||
return best;
|
||||
}
|
||||
|
||||
let bestChild = null;
|
||||
if (node.right === null) {
|
||||
bestChild = node.left;
|
||||
} else if (node.left === null) {
|
||||
bestChild = node.right;
|
||||
} else {
|
||||
if (point[node.dimension] < node.obj[node.dimension]) {
|
||||
bestChild = node.left;
|
||||
} else {
|
||||
bestChild = node.right;
|
||||
}
|
||||
}
|
||||
|
||||
best = search(best, bestChild);
|
||||
|
||||
let candidate = [null, null];
|
||||
for (let i = 0; i < dimensions; i += 1) {
|
||||
if (i === node.dimension) {
|
||||
candidate[i] = point[i];
|
||||
} else {
|
||||
candidate[i] = node.obj[i];
|
||||
}
|
||||
}
|
||||
|
||||
distance = Math.abs(calculateDistance(candidate, node.obj));
|
||||
|
||||
if (best.size < maxNodes || distance < best.peek()[1]) {
|
||||
let otherChild;
|
||||
if (bestChild === node.left) {
|
||||
otherChild = node.right;
|
||||
} else {
|
||||
otherChild = node.left;
|
||||
}
|
||||
if (otherChild !== null) {
|
||||
best = search(best, otherChild);
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
};
|
||||
|
||||
const best = search(null, root);
|
||||
const result = [];
|
||||
|
||||
for (let i=0; i < (Math.min(maxNodes, best.size)); i++) {
|
||||
result.push(best.removeHead());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Public Api
|
||||
const cache = new lru.create();
|
||||
|
||||
function generate(width, height, widthStep, heightStep) {
|
||||
const totalSize = Math.floor((width/widthStep) * (height/heightStep));
|
||||
const points = new Array(totalSize);
|
||||
let pos = 0;
|
||||
|
||||
for (let i = 0; i <= width; i += widthStep){
|
||||
for (let z = 0; z <= height; z += heightStep){
|
||||
points[pos++] = [i, z];
|
||||
}
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
function setup(tree, width, height, widthStep, heightStep) {
|
||||
const key = `${width}.${height}.${widthStep}.${heightStep}`;
|
||||
const root = lru.get(cache, key);
|
||||
|
||||
if (root instanceof Node) {
|
||||
tree.root = root;
|
||||
} else {
|
||||
const points = generate(width, height, widthStep, heightStep);
|
||||
tree.root = buildTree(null, points, 0);
|
||||
lru.set(cache, key, tree.root);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
function isInitialized(tree) {
|
||||
assert(tree instanceof KDTree);
|
||||
return tree.root !== null;
|
||||
}
|
||||
|
||||
function initialize(tree, points) {
|
||||
assert(goog.isArray(points));
|
||||
assert(tree instanceof KDTree);
|
||||
|
||||
tree.root = buildTree(null, points, 0);
|
||||
return tree;
|
||||
}
|
||||
|
||||
function create(points) {
|
||||
const tree = new KDTree();
|
||||
if (goog.isArray(points)) {
|
||||
return initialize(tree, points);
|
||||
} else {
|
||||
return tree;
|
||||
}
|
||||
};
|
||||
|
||||
function clear(tree) {
|
||||
assert(tree instanceof KDTree);
|
||||
tree.root = null;
|
||||
return tree;
|
||||
}
|
||||
|
||||
function nearest(tree, point, maxNodes) {
|
||||
assert(goog.isArray(point));
|
||||
assert(maxNodes >= 1);
|
||||
assert(isInitialized(tree));
|
||||
return searchNearest(tree.root, point, maxNodes);
|
||||
}
|
||||
|
||||
// Factory functions
|
||||
self.create = create;
|
||||
self.initialize = initialize;
|
||||
self.setup = setup;
|
||||
self.isInitialized = isInitialized;
|
||||
self.clear = clear;
|
||||
self.nearest = nearest;
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue