You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.2 KiB
97 lines
2.2 KiB
const conversions = require('./conversions'); |
|
|
|
/* |
|
This function routes a model to all other models. |
|
|
|
all functions that are routed have a property `.conversion` attached |
|
to the returned synthetic function. This property is an array |
|
of strings, each with the steps in between the 'from' and 'to' |
|
color models (inclusive). |
|
|
|
conversions that are not possible simply are not included. |
|
*/ |
|
|
|
function buildGraph() { |
|
const graph = {}; |
|
// https://jsperf.com/object-keys-vs-for-in-with-closure/3 |
|
const models = Object.keys(conversions); |
|
|
|
for (let len = models.length, i = 0; i < len; i++) { |
|
graph[models[i]] = { |
|
// http://jsperf.com/1-vs-infinity |
|
// micro-opt, but this is simple. |
|
distance: -1, |
|
parent: null |
|
}; |
|
} |
|
|
|
return graph; |
|
} |
|
|
|
// https://en.wikipedia.org/wiki/Breadth-first_search |
|
function deriveBFS(fromModel) { |
|
const graph = buildGraph(); |
|
const queue = [fromModel]; // Unshift -> queue -> pop |
|
|
|
graph[fromModel].distance = 0; |
|
|
|
while (queue.length) { |
|
const current = queue.pop(); |
|
const adjacents = Object.keys(conversions[current]); |
|
|
|
for (let len = adjacents.length, i = 0; i < len; i++) { |
|
const adjacent = adjacents[i]; |
|
const node = graph[adjacent]; |
|
|
|
if (node.distance === -1) { |
|
node.distance = graph[current].distance + 1; |
|
node.parent = current; |
|
queue.unshift(adjacent); |
|
} |
|
} |
|
} |
|
|
|
return graph; |
|
} |
|
|
|
function link(from, to) { |
|
return function (args) { |
|
return to(from(args)); |
|
}; |
|
} |
|
|
|
function wrapConversion(toModel, graph) { |
|
const path = [graph[toModel].parent, toModel]; |
|
let fn = conversions[graph[toModel].parent][toModel]; |
|
|
|
let cur = graph[toModel].parent; |
|
while (graph[cur].parent) { |
|
path.unshift(graph[cur].parent); |
|
fn = link(conversions[graph[cur].parent][cur], fn); |
|
cur = graph[cur].parent; |
|
} |
|
|
|
fn.conversion = path; |
|
return fn; |
|
} |
|
|
|
module.exports = function (fromModel) { |
|
const graph = deriveBFS(fromModel); |
|
const conversion = {}; |
|
|
|
const models = Object.keys(graph); |
|
for (let len = models.length, i = 0; i < len; i++) { |
|
const toModel = models[i]; |
|
const node = graph[toModel]; |
|
|
|
if (node.parent === null) { |
|
// No possible conversion, or this node is the source model. |
|
continue; |
|
} |
|
|
|
conversion[toModel] = wrapConversion(toModel, graph); |
|
} |
|
|
|
return conversion; |
|
}; |
|
|
|
|