├── .babelrc ├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.html ├── index.js ├── index.umd.js ├── logo.svg ├── package.json ├── rollup.config.js ├── test.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["latest", { 4 | "es2015": { 5 | "modules": false 6 | } 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "google"], 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | "sourceType": "module", 6 | "ecmaFeatures": { 7 | "jsx": true 8 | } 9 | }, 10 | "rules": { 11 | "semi": 2, 12 | "no-console": 0 13 | }, 14 | "env": { 15 | "node": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - node_modules 5 | notifications: 6 | email: false 7 | node_js: 8 | - '8' 9 | before_script: 10 | - npm prune 11 | after_success: 12 | - npm run semantic-release 13 | branches: 14 | except: 15 | - /^v\d+\.\d+\.\d+$/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 David Aerne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Closestᐁector 4 | [![Build Status](https://travis-ci.org/meodai/ClosestVector.svg?branch=master)](https://travis-ci.org/meodai/ClosestVector) 5 | 6 | Get closest Number / Point / Vector / VectorN from an array and caches the previous get request/response paris. 7 | 8 | ## Installation 9 | `npm install closestvector --save` or `yarn add closestvector` 10 | 11 | ## Usage 12 | ```javascript 13 | const Closest = require('closestvector'); 14 | const closest = new Closest([[255,0,0], [0,255,0], [0,0,255], [0,0,0]]); 15 | closest.get([200,130,213]) // => [0,0,255] 16 | ``` 17 | 18 | **if you wish to return every value only once:** 19 | ```javascript 20 | const closest = new Closest([[255,0,0], [0,255,0], [0,0,255], [0,0,0]], true); 21 | closest.get([200,130,213]) // => [0,0,255] closest Vector 22 | closest.get([200,130,213]) // => [255,0,0] next closest Vector 23 | closest.clearCache() // resets the returned elements 24 | closest.get([200,130,213]) // => [0,0,255] closest Vector 25 | ``` 26 | 27 | ## Examples 28 | ### Closest Vector2 29 | ```javascript 30 | const Closest = require('closestvector'); 31 | const closestVector = new Closest([[1,2],[222,6],[222,5],[222,4]]); 32 | 33 | closestVector.get([255,255]) // => {"closest":[222,6],"index":1} 34 | closestVector.get([2,5]) // => {"closest":[1,2],"index":0} 35 | closestVector.get([64,12]) // => {"closest":[1,2],"index":0} 36 | ``` 37 | 38 | ### Unique closest Vector2 39 | every vector can be retruned only once 40 | 41 | ```javascript 42 | const Closest = require('closestvector'); 43 | const closestUniqueVector = new Closest([[1,2],[222,6],[222,5],[222,4]], true); 44 | 45 | closestUniqueVector.get([255,255]) // => {"closest":[222,6],"index":1} 46 | closestUniqueVector.get([255,255]) // => {"closest":[222,5],"index":2} 47 | closestUniqueVector.get([255,255]) // => {"closest":[222,4],"index":3} 48 | closestUniqueVector.get([255,255]) // => {"closest":[1,2],"index":0} 49 | closestUniqueVector.get([255,255]) // => Null (Out of entries to return) 50 | closestUniqueVector.clearCache() 51 | closestUniqueVector.get([255,255]) // => {"closest":[222,6],"index":1} 52 | 53 | ``` 54 | 55 | ### Closest Number 56 | ```javascript 57 | const Closest = require('closestvector'); 58 | const closestNumber = new Closest([10,3,10,45,30,120]); 59 | 60 | closestNumber.get(10) // => {closest: 10, index: 0} 61 | closestNumber.get(100) // => {closest: 120, index: 5} 62 | closestNumber.get(100000) // => {closest: 120, index: 5} 63 | closestNumber.get(1) // => {closest: 3, index: 1} 64 | ``` 65 | 66 | ### Closest Vector3 or RGB Color 67 | ```javascript 68 | const Closest = require('closestvector'); 69 | const closestColor = new Closest([ 70 | [255,255,255], 71 | [0,0,0], 72 | [255,0,0], 73 | [0,255,0], 74 | [0,0,255], 75 | [0,255,255], 76 | [255,255,0] 77 | ]); 78 | closestColor.get([0,192,200]) // => {"closest":[0,255,255],"index":5} 79 | ``` 80 | 81 | ## How it works 82 | 83 | From [the Wikipedia article on the subject](http://en.wikipedia.org/wiki/Nearest_neighbor_search): 84 | > The simplest solution to the NNS problem is to compute the distance from the query point 85 | > to every other point in the database, keeping track of the "best so far". This algorithm, 86 | > sometimes referred to as the naive approach, has a running time of *O(Nd)* where *N* is 87 | > the cardinality of *S* and *d* is the dimensionality of *M*. There are no search data 88 | > structures to maintain, so linear search has no space complexity beyond the storage of the 89 | > database. Naive search can, on average, outperform space partitioning approaches on higher 90 | > dimensional spaces. 91 | 92 | ClosestVector is inspired by [nearest-color] and was rewritten to solve snapping to coordinates in a less specific way. As nearest-color it uses the naive approach and caches the requests made, so the diffing only happens if the vector is requested for the first time. 93 | 94 | [nearest-color]: https://github.com/dtao/nearest-color/ 95 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Closestᐁector - Demo Page 7 | 103 | 104 | 105 | 106 |
107 |

108 | 109 | 142 | 143 | Closestᐁector 144 |

145 |

Super fast lightweight and dependency free library to get closest Number / Point / Vector / VectorN from an array 146 | with caching and stuff

147 |
148 |

Vector 2

149 |

150 | Move your mouse cursor to highlight one of 152 |

153 | (it took 0 ms to find the last point) 154 |
155 |
156 |

Vector 3

157 |

158 | Find the closest color-name in a set of ~26k colors/name pairs based on RGB coordinates. 159 |
160 |

164 | (it took 0 ms to find the closest color in RGB 165 | values) 166 | 167 |

168 |
169 | 178 | 179 |
180 | 181 | 182 | 192 | 193 | 233 | 234 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Return closest Number/Vector2/Vector3/VectorN from a given list 3 | * uses caching for faster response. Has the ability to return every match 4 | * only once. 5 | */ 6 | export default class Closest { 7 | /** 8 | * Creates an instance of Closest. 9 | * @param {Array} list Elements of reference can be an Array of Numbers 10 | * or Array's with an equal length 11 | * @param {Boolean} unique If set to true, every entry from `list` 12 | * can be returned only once 13 | * unit clearCache() is called 14 | */ 15 | constructor(list, unique) { 16 | // creates a copy of list 17 | this.list = Array.from(list); 18 | 19 | this.dimensions = Closest.getDimensions(list[0]); 20 | 21 | this.unique = unique; 22 | 23 | // sets the adequate diff method based on the depth of the vectors 24 | this.diff = this.dimensions > 1 ? Closest.nDimensionalDiff(this.dimensions) 25 | : Closest.oneDimensionalDiff; 26 | // console.log(this.diff) 27 | // inits the cache and previouslyReturnedIndexes properties 28 | this.clearCache(false); 29 | } 30 | 31 | /** 32 | * determines if the items in the list are simple numbers or arrays 33 | * @static 34 | * @param {Number|Array} item 35 | * @return {Number} number of dimensions (1 being a simple number, 36 | * everything above is an array) 37 | */ 38 | static getDimensions(item) { 39 | return typeof item == 'number' ? 1 : item.length; 40 | } 41 | 42 | /** 43 | * diff function for simple numbers 44 | * @static 45 | * @param {Number} val1 46 | * @param {Number} val2 47 | * @return {Number} Abstract difference between two numbers 48 | */ 49 | static oneDimensionalDiff(val1, val2) { 50 | return Math.abs(val1-val2); 51 | } 52 | 53 | /** 54 | * diff function for array's of N numbers 55 | * @static 56 | * @param {Number} dimensions number of dimensions of your vector 57 | * @return {Function} returns the adequate diff function 58 | * Euclidean distance 59 | * (https://en.wikipedia.org/wiki/Euclidean_distance) 60 | */ 61 | static nDimensionalDiff(dimensions) { 62 | if (dimensions == 2) { 63 | return (val1, val2) => ( 64 | (val1[0] - val2[0]) * (val1[0] - val2[0]) + 65 | (val1[1] - val2[1]) * (val1[1] - val2[1]) 66 | ); 67 | } else if (dimensions == 3) { 68 | return (val1, val2) => ( 69 | (val1[0] - val2[0]) * (val1[0] - val2[0]) + 70 | (val1[1] - val2[1]) * (val1[1] - val2[1]) + 71 | (val1[2] - val2[2]) * (val1[2] - val2[2]) 72 | ); 73 | } else { 74 | // elegant but slow solution 75 | return (val1, val2) => ( 76 | val1.reduce( 77 | (acc, val, i) => ((val - val2[i]) * (val - val2[i]) + acc) 78 | , 0) 79 | ); 80 | } 81 | } 82 | 83 | /** 84 | Public method to rest cached value / result paris 85 | * especially if set to unique (return every match only once) 86 | * you may want to reset the previously returned indexes 87 | * @param {Boolean} indexOnly if you are using "unique" mode only the returned 88 | * indexes are cleared by default 89 | */ 90 | clearCache(indexOnly = this.unique) { 91 | if (!indexOnly) { 92 | this.cache = {}; 93 | } 94 | this.previouslyReturnedIndexes = []; 95 | } 96 | 97 | /** 98 | * gets the closes Number/VectorN 99 | * @param {Number|Array} val reference number or array 100 | * @return {Object|Null} closes match within lists containing 101 | * { 102 | * closest: {Number|Array} closest entry from list 103 | * index: {Number} index within list 104 | * distance: {Number} Distance within the 105 | * coordinate system 106 | * } 107 | */ 108 | get(val) { 109 | let minDistance = Infinity; 110 | let index = 0; 111 | let closest = this.list[index]; 112 | 113 | // is there a better way to do this? If "val" is only a number, it seams 114 | // like a big overhead to JSON stringify it every-time, I don't see an other 115 | // way when val is an array thought. Other than something like 116 | // cache[val[0]][val[1]][val[3]] or whatever 117 | const valUID = JSON.stringify(val); 118 | 119 | // returns previously found match 120 | if (!this.unique && this.cache.hasOwnProperty(valUID)) { 121 | return this.cache[valUID]; 122 | } 123 | 124 | // if set to return every value in the list only once 125 | // and being out of entries in the list 126 | if ( 127 | this.unique && this.previouslyReturnedIndexes.length === this.list.length 128 | ) { 129 | return null; 130 | } 131 | 132 | for (let i = 0; i < this.list.length; i++) { 133 | // skip if set to unique and value was returned previously 134 | if (!(this.unique && this.previouslyReturnedIndexes.indexOf(i) > -1) ) { 135 | const distance = this.diff(val, this.list[i]); 136 | if (distance < minDistance) { 137 | minDistance = distance; 138 | index = i; 139 | closest = this.list[i]; 140 | } 141 | } 142 | } 143 | 144 | // save previously returned indexes if set to unique mode, 145 | if (this.unique) { 146 | this.previouslyReturnedIndexes.push(index); 147 | } 148 | 149 | // return and save in cache 150 | return this.cache[valUID] = {closest, index}; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /index.umd.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 3 | typeof define === 'function' && define.amd ? define(factory) : 4 | (global = global || self, global.Closest = factory()); 5 | }(this, function () { 'use strict'; 6 | 7 | /** 8 | * Return closest Number/Vector2/Vector3/VectorN from a given list 9 | * uses caching for faster response. Has the ability to return every match 10 | * only once. 11 | */ 12 | class Closest { 13 | /** 14 | * Creates an instance of Closest. 15 | * @param {Array} list Elements of reference can be an Array of Numbers 16 | * or Array's with an equal length 17 | * @param {Boolean} unique If set to true, every entry from `list` 18 | * can be returned only once 19 | * unit clearCache() is called 20 | */ 21 | constructor(list, unique) { 22 | // creates a copy of list 23 | this.list = Array.from(list); 24 | 25 | this.dimensions = Closest.getDimensions(list[0]); 26 | 27 | this.unique = unique; 28 | 29 | // sets the adequate diff method based on the depth of the vectors 30 | this.diff = this.dimensions > 1 ? Closest.nDimensionalDiff(this.dimensions) 31 | : Closest.oneDimensionalDiff; 32 | // console.log(this.diff) 33 | // inits the cache and previouslyReturnedIndexes properties 34 | this.clearCache(false); 35 | } 36 | 37 | /** 38 | * determines if the items in the list are simple numbers or arrays 39 | * @static 40 | * @param {Number|Array} item 41 | * @return {Number} number of dimensions (1 being a simple number, 42 | * everything above is an array) 43 | */ 44 | static getDimensions(item) { 45 | return typeof item == 'number' ? 1 : item.length; 46 | } 47 | 48 | /** 49 | * diff function for simple numbers 50 | * @static 51 | * @param {Number} val1 52 | * @param {Number} val2 53 | * @return {Number} Abstract difference between two numbers 54 | */ 55 | static oneDimensionalDiff(val1, val2) { 56 | return Math.abs(val1-val2); 57 | } 58 | 59 | /** 60 | * diff function for array's of N numbers 61 | * @static 62 | * @param {Number} dimensions number of dimensions of your vector 63 | * @return {Function} returns the adequate diff function 64 | * Euclidean distance 65 | * (https://en.wikipedia.org/wiki/Euclidean_distance) 66 | */ 67 | static nDimensionalDiff(dimensions) { 68 | if (dimensions == 2) { 69 | return (val1, val2) => ( 70 | (val1[0] - val2[0]) * (val1[0] - val2[0]) + 71 | (val1[1] - val2[1]) * (val1[1] - val2[1]) 72 | ); 73 | } else if (dimensions == 3) { 74 | return (val1, val2) => ( 75 | (val1[0] - val2[0]) * (val1[0] - val2[0]) + 76 | (val1[1] - val2[1]) * (val1[1] - val2[1]) + 77 | (val1[2] - val2[2]) * (val1[2] - val2[2]) 78 | ); 79 | } else { 80 | // elegant but slow solution 81 | return (val1, val2) => ( 82 | val1.reduce( 83 | (acc, val, i) => ((val - val2[i]) * (val - val2[i]) + acc) 84 | , 0) 85 | ); 86 | } 87 | } 88 | 89 | /** 90 | Public method to rest cached value / result paris 91 | * especially if set to unique (return every match only once) 92 | * you may want to reset the previously returned indexes 93 | * @param {Boolean} indexOnly if you are using "unique" mode only the returned 94 | * indexes are cleared by default 95 | */ 96 | clearCache(indexOnly = this.unique) { 97 | if (!indexOnly) { 98 | this.cache = {}; 99 | } 100 | this.previouslyReturnedIndexes = []; 101 | } 102 | 103 | /** 104 | * gets the closes Number/VectorN 105 | * @param {Number|Array} val reference number or array 106 | * @return {Object|Null} closes match within lists containing 107 | * { 108 | * closest: {Number|Array} closest entry from list 109 | * index: {Number} index within list 110 | * distance: {Number} Distance within the 111 | * coordinate system 112 | * } 113 | */ 114 | get(val) { 115 | let minDistance = Infinity; 116 | let index = 0; 117 | let closest = this.list[index]; 118 | 119 | // is there a better way to do this? If "val" is only a number, it seams 120 | // like a big overhead to JSON stringify it every-time, I don't see an other 121 | // way when val is an array thought. Other than something like 122 | // cache[val[0]][val[1]][val[3]] or whatever 123 | const valUID = JSON.stringify(val); 124 | 125 | // returns previously found match 126 | if (!this.unique && this.cache.hasOwnProperty(valUID)) { 127 | return this.cache[valUID]; 128 | } 129 | 130 | // if set to return every value in the list only once 131 | // and being out of entries in the list 132 | if ( 133 | this.unique && this.previouslyReturnedIndexes.length === this.list.length 134 | ) { 135 | return null; 136 | } 137 | 138 | for (let i = 0; i < this.list.length; i++) { 139 | // skip if set to unique and value was returned previously 140 | if (!(this.unique && this.previouslyReturnedIndexes.indexOf(i) > -1) ) { 141 | const distance = this.diff(val, this.list[i]); 142 | if (distance < minDistance) { 143 | minDistance = distance; 144 | index = i; 145 | closest = this.list[i]; 146 | } 147 | } 148 | } 149 | 150 | // save previously returned indexes if set to unique mode, 151 | if (this.unique) { 152 | this.previouslyReturnedIndexes.push(index); 153 | } 154 | 155 | // return and save in cache 156 | return this.cache[valUID] = {closest, index}; 157 | } 158 | } 159 | 160 | return Closest; 161 | 162 | })); 163 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | closestvector -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "closestvector", 3 | "version": "0.6.1", 4 | "description": "returns the closest value / vector / vectorN from an array", 5 | "main": "index.umd.js", 6 | "es2015": "index.js", 7 | "scripts": { 8 | "pretest": "npm run build", 9 | "test": "mocha", 10 | "build": "rollup --config", 11 | "semantic-release": "semantic-release pre && npm publish && semantic-release post" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/meodai/ClosestVector.git" 16 | }, 17 | "keywords": [ 18 | "2d", 19 | "3d", 20 | "vector", 21 | "vectors", 22 | "distance", 23 | "diff", 24 | "difference" 25 | ], 26 | "author": "meodai", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/meodai/ClosestVector/issues" 30 | }, 31 | "homepage": "https://github.com/meodai/ClosestVector#readme", 32 | "devDependencies": { 33 | "chai": "^4.2.0", 34 | "eslint": "^5.15.1", 35 | "eslint-config-google": "^0.12.0", 36 | "mocha": "^6.0.2", 37 | "rollup": "^1.16.2", 38 | "semantic-release": "^17.2.3", 39 | "rollup-plugin-uglify": "^6.0.4" 40 | }, 41 | "standard": { 42 | "env": { 43 | "mocha": true 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import uglify from 'rollup-plugin-uglify'; 2 | 3 | export default { 4 | input: 'index.js', 5 | output: { 6 | file: 'index.umd.js', 7 | format: 'umd', 8 | name: 'Closest', 9 | }, 10 | /*plugins: [ 11 | uglify.uglify(), 12 | ],*/ 13 | }; 14 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const Closest = require('.'); 3 | 4 | const simple = new Closest([1]); 5 | 6 | describe('Closest', () => { 7 | it('Closest is a function', () => { 8 | expect(Closest).to.be.an('function'); 9 | }); 10 | 11 | it('be an instance of Closest', () => { 12 | expect(new Closest([1])).to.be.an.instanceof(Closest); 13 | }); 14 | 15 | it('return correct closest vectors2', () => { 16 | const closestVector = new Closest([[1,2],[2,2],[4,4],[255,255]]); 17 | 18 | closestVector.get([255,255]); 19 | closestVector.get([2,5]); 20 | closestVector.get([64,12]); 21 | 22 | expect(closestVector.get([255,255])).to.deep.equal({ 23 | "closest":[255,255], 24 | "index":3 25 | }); 26 | }); 27 | 28 | it('Closest.getDimensions to return 1 on number types', () => { 29 | expect(Closest.getDimensions(12.12)).to.be.equal(1); 30 | expect(Closest.getDimensions(1)).to.be.equal(1); 31 | expect(Closest.getDimensions(Infinity)).to.be.equal(1); 32 | }); 33 | 34 | it('Closest.getDimensions to return correct amount of dimensions', () => { 35 | expect(Closest.getDimensions(10)).to.be.equal(1); 36 | const a = new Array(100).fill('1'); 37 | expect(Closest.getDimensions(a)).to.be.equal(a.length); 38 | }); 39 | 40 | it('Closest.oneDimensionalDiff to diff simple numbers correctly', () => { 41 | expect(Closest.oneDimensionalDiff(0,10)).to.be.equal(10); 42 | expect(Closest.oneDimensionalDiff(-10,10)).to.be.equal(20); 43 | expect(Closest.oneDimensionalDiff(-20,-1)).to.be.equal(19); 44 | }); 45 | 46 | it('Closest.oneDimensionalDiff to diff simple numbers correctly', () => { 47 | expect(Closest.oneDimensionalDiff(0,10)).to.be.equal(10); 48 | expect(Closest.oneDimensionalDiff(-10,10)).to.be.equal(20); 49 | expect(Closest.oneDimensionalDiff(-20,-1)).to.be.equal(19); 50 | expect(Closest.oneDimensionalDiff(0,0)).to.be.equal(0); 51 | expect(Closest.oneDimensionalDiff(0.1,0.000001)).to.be.equal(0.099999); 52 | }); 53 | 54 | it('Closest.nDimensionalDiff to return correct difference between two Vector2', () => { 55 | expect(Closest.nDimensionalDiff(2)([10,10],[10,10])).to.be.equal(0); 56 | expect(Closest.nDimensionalDiff(2)([10,10],[100,100])).to.be.equal( 57 | (10 - 100) * (10 - 100) + 58 | (10 - 100) * (10 - 100) 59 | ); 60 | 61 | expect(Closest.nDimensionalDiff(2)([-1,1],[100,100])).to.be.equal( 62 | (-1 - 100) * (-1 - 100) + 63 | (1 - 100) * (1 - 100) 64 | ); 65 | }); 66 | 67 | it('Closest.nDimensionalDiff to return correct difference between two Vector3', () => { 68 | expect(Closest.nDimensionalDiff(3)([255,255,255],[255,255,255])).to.be.equal(0); 69 | expect(Closest.nDimensionalDiff(3)([255,255,255],[0,0,0])).to.be.equal( 70 | (255 - 0) * (255 - 0) + 71 | (255 - 0) * (255 - 0) + 72 | (255 - 0) * (255 - 0) 73 | ); 74 | }); 75 | 76 | it('Clear chache correctly in "unique" mode', () => { 77 | const closest = new Closest([1,2,3,4], true); 78 | 79 | expect(closest.get(1).closest).to.be.equal(1); 80 | expect(closest.get(1).closest).to.be.equal(2); 81 | 82 | closest.clearCache(); 83 | 84 | expect(closest.get(1).closest).to.be.equal(1); 85 | }); 86 | 87 | }); --------------------------------------------------------------------------------