@allmaps/transform
Version:
Coordinate transformation functions
130 lines (129 loc) • 4.42 kB
JavaScript
import { BasePolynomialTransformation } from './BasePolynomialTransformation.js';
/**
* 2D First-order Polynomial transformation
*
* This transformation is a composition of a translation, rotation, scaling and shearing.
*/
export class Polynomial1 extends BasePolynomialTransformation {
constructor(sourcePoints, destinationPoints) {
super(sourcePoints, destinationPoints, 1);
}
getSourcePointCoefsArray(sourcePoint) {
return Polynomial1.getPolynomial1SourcePointCoefsArray(sourcePoint);
}
/**
* Get 1x3 coefsArray, populating the Nx3 coefsArrayMatrix
* 1 x0 y0
* 1 x1 y1
* 1 x2 y2
* ...
*
* @param sourcePoint
*/
static getPolynomial1SourcePointCoefsArray(sourcePoint) {
return [1, sourcePoint[0], sourcePoint[1]];
}
getHomogeneousTransform() {
if (!this.weightsArrays) {
return undefined;
}
return [
this.weightsArrays[0][1],
this.weightsArrays[1][1],
this.weightsArrays[0][2],
this.weightsArrays[1][2],
this.weightsArrays[0][0],
this.weightsArrays[1][0]
];
}
setWeightsArraysFromHomogeneousTransform(homogeneousTransform) {
this.weightsArrays = [
[
homogeneousTransform[4],
homogeneousTransform[0],
homogeneousTransform[2]
],
[
homogeneousTransform[5],
homogeneousTransform[1],
homogeneousTransform[3]
]
];
}
getMeasures() {
if (!this.weightsArrays) {
this.solve();
}
if (!this.weightsArrays) {
throw new Error('Weights not computed');
}
const measures = {};
// From: https://stackoverflow.com/questions/12469770/get-skew-or-rotation-value-from-affine-transformation-matrix
measures.translation = [this.weightsArrays[0][0], this.weightsArrays[1][0]];
const a = this.weightsArrays[0][1];
const b = this.weightsArrays[1][1];
const c = this.weightsArrays[0][2];
const d = this.weightsArrays[1][2];
const delta = a * d - b * c;
// Apply the QR-like decomposition.
if (a != 0 || b != 0) {
const r = Math.sqrt(a * a + b * b);
measures.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
measures.scales = [r, delta / r];
measures.shears = [Math.atan((a * c + b * d) / (r * r)), 0];
}
else if (c != 0 || d != 0) {
const s = Math.sqrt(c * c + d * d);
measures.rotation =
Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
measures.scales = [delta / s, s];
measures.shears = [0, Math.atan((a * c + b * d) / (s * s))];
}
else {
// a = b = c = d = 0
}
return measures;
}
evaluateFunction(newSourcePoint) {
if (!this.weightsArrays) {
this.solve();
}
if (!this.weightsArrays) {
throw new Error('Weights not computed');
}
const newDestinationPoint = [0, 0];
for (let i = 0; i < 2; i++) {
newDestinationPoint[i] +=
this.weightsArrays[i][0] +
this.weightsArrays[i][1] * newSourcePoint[0] +
this.weightsArrays[i][2] * newSourcePoint[1];
}
return newDestinationPoint;
}
evaluatePartialDerivativeX(_newSourcePoint) {
if (!this.weightsArrays) {
this.solve();
}
if (!this.weightsArrays) {
throw new Error('Weights not computed');
}
const newDestinationPointPartDerX = [0, 0];
for (let i = 0; i < 2; i++) {
newDestinationPointPartDerX[i] += this.weightsArrays[i][1];
}
return newDestinationPointPartDerX;
}
evaluatePartialDerivativeY(_newSourcePoint) {
if (!this.weightsArrays) {
this.solve();
}
if (!this.weightsArrays) {
throw new Error('Weights not computed');
}
const newDestinationPointPartDerY = [0, 0];
for (let i = 0; i < 2; i++) {
newDestinationPointPartDerY[i] += this.weightsArrays[i][2];
}
return newDestinationPointPartDerY;
}
}