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.
		
		
		
		
			
				
					98 lines
				
				2.2 KiB
			
		
		
			
		
	
	
					98 lines
				
				2.2 KiB
			| 
											11 months ago
										 | 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; | ||
|  | }; | ||
|  | 
 |