/** * Pick a certain amount of unique objects from sourceList. * If the amount requested is more than total number of objects in sourceList, * only everything available in sourceList and nothing more will be picked. * @param {list} sourceList * @param {number} amount * @return {object} - {sample: list, remainder: list} sample is the list of selected objects while remainder is the list of those unselected. */ export function takeSampleFrom(sourceList, amount) { let randElements = [], max = sourceList.length; if (amount >= max) { return {sample: sourceList, remainder: {}}; } for (let i = 0; i < amount; ++i) { let rand = sourceList[Math.floor((Math.random() * max))]; // Re-random until suitable value is found. while (randElements.includes(rand)) { rand = sourceList[Math.floor((Math.random() * max))]; } randElements.push(rand); } var remainder = sourceList.filter(function (obj) { return !randElements.includes(obj); }); return { sample: randElements, remainder: remainder }; } /** * With a circle radius r, and center at (h,k), * Find the coordinate of a point at angle degrees * @param {number} h * @param {number} k * @param {number} angle * @param {number} r * @return {object} - coordinate {x: number, y: number} of the point */ export function pointOnCircle(h, k, angle, r) { let x = h + r*Math.cos(toRadians(angle)); let y = k + r*Math.sin(toRadians(angle)); return { x: x, y: y }; } function toRadians(degrees) { return degrees * (Math.PI / 180); } /** * Find the sum of ( difference between high and low dimensional distance ) * between a node and each of the samples. The high dimensional distances are * precalculated and stored in realDistances. * @param {object} node - a single node, must have x and y properties * @param {list} samples - list of other node objects to compare against * @param {list} realDistances - list of number distances between the node to each of the samples. Index must correspond to that of samples. * @return {number} - Sum of distances differences */ export function sumDistError(node, samples, realDistances) { let total = 0.0; for (let i = 0; i < samples.length; i++) { let sample = samples[i]; let lowDDistance = Math.hypot(sample.x - node.x, sample.y - node.y); total += Math.abs(lowDDistance - realDistances[i]); } return total; }