voluptasquisquam
Version:
Image processing and manipulation in JavaScript
139 lines (130 loc) • 3.9 kB
JavaScript
/**
* Rounds all the x and y values of an array of points
* @param {Array<Array<number>>} points
* @return {Array<Array<number>>} modified input value
* @private
*/
export function round(points) {
for (let i = 0; i < points.length; i++) {
points[i][0] = Math.round(points[i][0]);
points[i][1] = Math.round(points[i][1]);
}
return points;
}
/**
* Calculates a new point that is the difference p1 - p2
* @param {Array<number>} p1
* @param {Array<number>} p2
* @return {Array<number>}
* @private
*/
export function difference(p1, p2) {
return [p1[0] - p2[0], p1[1] - p2[1]];
}
/**
* Normalize a point
* @param {Array<number>} p
* @return {Array<number>}
* @private
*/
export function normalize(p) {
let length = Math.sqrt(p[0] ** 2 + p[1] ** 2);
return [p[0] / length, p[1] / length];
}
/**
* We rotate an array of points
* @param {number} radians
* @param {Array<Array<number>>} srcPoints
* @param {Array<Array<number>>} destPoints
* @return {Array<Array<number>>}
* @private
*/
export function rotate(radians, srcPoints, destPoints) {
if (destPoints === undefined) destPoints = new Array(srcPoints.length);
let cos = Math.cos(radians);
let sin = Math.sin(radians);
for (let i = 0; i < destPoints.length; ++i) {
destPoints[i] = [
cos * srcPoints[i][0] - sin * srcPoints[i][1],
sin * srcPoints[i][0] + cos * srcPoints[i][1]
];
}
return destPoints;
}
/**
* Dot products of 2 points assuming vectors starting from (0,0)
* @param {Array<number>} p1
* @param {Array<number>} p2
* @return {number}
* @private
*/
export function dot(p1, p2) {
return p1[0] * p2[0] + p1[1] * p2[1];
}
/**
* Returns the angle between 3 points. The first one is a common point
* @param {Array<number>} origin
* @param {Array<number>} p1
* @param {Array<number>} p2
* @return {number}
* @private
*/
export function angle(origin, p1, p2) {
let v1 = normalize(difference(p1, origin));
let v2 = normalize(difference(p2, origin));
let dotProduct = dot(v1, v2);
// TODO this code is not correct because it may yield the opposite angle
return Math.acos(dotProduct);
}
/**
* Returns the 4 points of an horizontal rectangle that includes all the points
* @param {Array<Array<number>>} points
* @return {Array<Array<number>>}
* @private
*/
export function boundary(points) {
let minMaxValues = minMax(points);
let xMin = minMaxValues[0][0];
let yMin = minMaxValues[0][1];
let xMax = minMaxValues[1][0];
let yMax = minMaxValues[1][1];
return [[xMin, yMin], [xMax, yMin], [xMax, yMax], [xMin, yMax]];
}
/**
* Returns 2 points with minimal and maximal XY
* @param {Array<Array<number>>} points
* @return {Array<Array<number>>}
* @private
*/
export function minMax(points) {
let xMin = +Infinity;
let yMin = +Infinity;
let xMax = -Infinity;
let yMax = -Infinity;
for (let i = 0; i < points.length; i++) {
if (points[i][0] < xMin) xMin = points[i][0];
if (points[i][0] > xMax) xMax = points[i][0];
if (points[i][1] < yMin) yMin = points[i][1];
if (points[i][1] < yMax) yMax = points[i][1];
}
return [[xMin, yMin], [xMax, yMax]];
}
/**
* Moves the minX, minY to 0,0
* All the points will be positive after this move
* @param {Array<Array<number>>} srcPoints
* @param {Array<Array<number>>} destPoints
* @return {Array<Array<number>>}
* @private
*/
export function moveToZeroZero(srcPoints, destPoints) {
if (destPoints === undefined) destPoints = new Array(srcPoints.length);
let minMaxValues = minMax(srcPoints);
let xMin = minMaxValues[0][0];
let yMin = minMaxValues[0][1];
for (let i = 0; i < srcPoints.length; i++) {
destPoints[i][0] = srcPoints[i][0] - xMin;
destPoints[i][1] = srcPoints[i][1] - yMin;
}
return destPoints;
}