Welcome to the Nudged interface documentation!
The API follows a functional and immutable paradigm without classes.
Thus all the functions take in and return only plain objects and values
such as { x: 1, y: 2 }
. The functions never modify the given objects,
never cause side effects, and never memorize previous calls.
In contrast to object-oriented programming, the features are
implemented as pure functions that are grouped
in modules aka namespaces instead of classes.
See the available modules below.
- nudged.estimate
- nudged.estimators
- nudged.point
- nudged.transform
- nudged.analysis
- nudged.tolerance
- nudged.version
Estimates a transformation with the selected estimator and constraints. See nudged.estimators for available estimators.
Parameters:
params
, an object with properties:estimator
- Required string. The name of the estimator.
- Defines the freedom of the transform to compute.
- One of the following: 'I', 'L', 'X', 'Y', 'T', 'S', 'R', 'TS', 'TR', 'SR', 'TSR'
domain
- required array of points
{ x, y }
. - The points before the transform.
- required array of points
range
- required array of points
{ x, y }
. - The points after the transform.
- required array of points
center
- optional point.
- Used as the center by the estimators 'S', 'R', and 'SR'.
- If an estimator other than these is selected, the center has no effect to the estimation.
angle
- optional number. Angle in radians.
- Used by the estimator 'L'.
- If an estimator other than 'L' is selected, the angle has no effect to the estimation.
Return:
Internally, this calls the function of the selected estimator.
Therefore, if you desire maximal efficiency instead of flexibility,
use the estimator functions directly via nudged.estimators,
like for example [nudged.estimators.R](#nudgedestimatorsR)(domain, range, center)
Example:
> const domain = [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 2 }]
> const range = [{ x: 1, y: 1 }, { x: 1, y: 3 }, { x: -1, y: 2 }]
> const center = { x: 0, y: 0 }
> const tr = nudged.estimate({
estimator: 'SR',
domain: domain,
range: range,
center: center
})
> nudged.transform.getScale(tr)
1.242259
> nudged.transform.getRotation(tr)
1.107148
A collection of estimator functions. Call these directly instead of the general nudged.estimate for a bit more efficiency by saving one function call.
- nudged.estimators.I
- nudged.estimators.L
- nudged.estimators.X
- nudged.estimators.Y
- nudged.estimators.T
- nudged.estimators.S
- nudged.estimators.R
- nudged.estimators.TS
- nudged.estimators.TR
- nudged.estimators.SR
- nudged.estimators.TSR
The trivial estimator; The estimate is always the identity transformation.
Example:
> nudged.estimators.I(domain, range)
{ a: 1, b: 0, x: 0, y: 0 }
Estimate translation along a line at the given angle.
Parameters:
Return:
Estimate horizontal translation that is a translation along x-axis.
Parameters:
Return:
Estimate vertical translation that is a translation along y-axis.
Parameters:
Return:
Estimate translation that maps domain points close to range points.
Parameters:
Return:
Estimate a scaling around the given center. In other words, estimate a homothety.
Parameters:
Return:
Estimate rotation around a fixed center point
Parameters:
Return:
Estimate translation with scaling.
Parameters:
Return:
Estimate translation with rotation.
Parameters:
Return:
Estimate optimal transformation given the domain and the range so that the center point remains fixed. Example use cases:
- Transform an image that has one corner fixed with a pin.
- Allow only scale and rotation by fixing the middle of the object.
Parameters:
domain
- array of points
range
- array of points
center
- a point that must remain constant in the tranformation.
Return:
Estimate a non-reflective similarity transformation. In other words, an affine transformation where translation, positive scaling, and rotation are allowed.
Parameters:
Return:
A set of operators for 2D point objects { x, y }
.
- nudged.point.almostEqual
- nudged.point.create
- nudged.point.distance
- nudged.point.equal
- nudged.point.fromArray
- nudged.point.offset
- nudged.point.polarOffset
- nudged.point.toArray
- nudged.point.transform
- nudged.point.transformMany
- nudged.point.validate
Test if two points are almost equal within the limit given by the optional tolerance parameter.
Parameters:
p
- a point
q
- a point
tolerance
- Optional number
- Defaults to nudged.tolerance.
- Set to
0
for strict comparison.
Return:
- boolean
Example:
> nudged.point.almostEqual({ x: 0, y: 0 }, { x: 0, y: 1.23e-16 })
true
> nudged.point.almostEqual({ x: 0, y: 0 }, { x: 0, y: 0.1 })
false
> nudged.point.almostEqual({ x: 0, y: 0 }, { x: 0, y: 0.1 }, 0.2)
true
Create a point object.
Parameters:
x
- a number
y
- a number
Return:
- a point
{ x, y }
The Euclidean distance between two points. Also called the Euclidean norm alias L2-norm.
Parameters:
Return:
- number, the distance from p to q (= distance from q to p)
Thest if the coordinates of two points are strictly equal.
Parameters:
Return:
- a boolean
Create a point { x, y }
from an array [x, y].
Parameters:
arrp
- an array with two elements
Return:
- a point
Offset a point by scalars dx dy.
Parameters:
p
- a point
dx
- a horizontal offset
dy
- a vertical offset
Return:
- a point, translated by the vector
{ x: dx, y: dy }
Create a point away from p at the given distance and angle.
Parameters:
p
- a point
distance
- a number
angle
- a number, angle in radians.
- The angle
0
is towards pos. x-axis and grows towards pos. y-axis.
Return:
- a point
Example:
> nudged.point.polarOffset({ x: 1, y: 0 }, 5, Math.PI / 2)
{ x: 1, y: 5 }
Represent a point { x, y }
in two-element array [x, y]
Parameters:
p
- a point
Return:
- an array
[x, y]
Transform a point. The point is first scaled and rotated around origin and then translated.
Parameters:
Return:
- a point, the transformed point
Example:
> const tr = nudged.transform.ROT90
> nudged.point.transform({ x: 1, y: 0 }, tr)
{ x: 0, y: 1 }
Transform an array of points
Parameters:
Return:
- an array of points, transformed
Example:
> const tr = nudged.transform.ROT90
> const ps = [{ x: 1, y: 0}, { x: 0, y: 1 }]
> nudged.point.transformMany(ps, tr)
[{ x: 0, y: 1 }, { x: -1, y: 0 }]
Check if the point is a valid point object.
Parameters:
p
- a point
Return:
- a boolean
Example:
> nudged.point.validate({ x: 1, y: 0 })
true
> nudged.point.validate({ x: 1 })
false
A transform is a plain object with the structure { a, b, x, y }
.
It defines a transformation matrix, and to be exact, an
augmented affine
non-reflective similarity
transformation matrix.
Such transformation matrices are a compact way to represent
translation, rotation, and scaling in a single 3x3 matrix.
The matrix that the transform represents has the following elements:
┌ ┐
│ a -b x │
│ b a y │
│ 0 0 1 │
└ ┘
- nudged.transform.SINGULAR
- nudged.transform.IDENTITY
- nudged.transform.ROT45
- nudged.transform.ROT90
- nudged.transform.ROT180
- nudged.transform.ROT270
- nudged.transform.HALF
- nudged.transform.X2
- nudged.transform.almostEqual
- nudged.transform.compose
- nudged.transform.create
- nudged.transform.equal
- nudged.transform.fromArray
- nudged.transform.fromPolar
- nudged.transform.fromRotation
- nudged.transform.fromScale
- nudged.transform.fromString
- nudged.transform.fromTranslation
- nudged.transform.getRotation
- nudged.transform.getScale
- nudged.transform.getTranslation
- nudged.transform.multiply
- nudged.transform.inverse
- nudged.transform.rotateBy
- nudged.transform.rotateTo
- nudged.transform.scaleBy
- nudged.transform.scaleTo
- nudged.transform.toArray
- nudged.transform.toMatrix
- nudged.transform.toString
- nudged.transform.translateBy
- nudged.transform.translateTo
- nudged.transform.validate
Singular transform, resembles multiplication by 0.
Identity transform, resembles multiplication by 1 in the way that it does not have any effect. You can use it as a starting point to build other transformations.
const I = nudged.transform.IDENTITY
const center = { x: 320, y: 240 }
const angle = Math.PI / 5
const rotation = nudged.transform.rotateBy(I, center, angle)
A prebuilt transform. Rotates around { x: 0, y: 0 }
by 45 degrees.
Example:
> const R = nudged.transform.ROT45
> nudged.transform.getRotation(R) * 360 / (2 * Math.PI)
45
> nudged.point.transform({ x: 1, y: 0 }, R)
{ x: 0.7071..., y: 0.7071... }
A prebuilt transform. Rotates around { x: 0, y: 0 }
by 90 degrees.
A prebuilt transform. Rotates around { x: 0, y: 0 }
by 180 degrees.
A prebuilt transform. Rotates around { x: 0, y: 0 }
by 270 degrees (= 3/4 turn = 3π/2).
A prebuilt transform. Scales towards { x: 0, y: 0 }
by the factor of 0.5.
A prebuilt transform. Scales away from { x: 0, y: 0 }
by the factor of 2.
Are two transforms almost equal? Due to the limitations of floating point precision, most operations have a bit of numerical error in their results. Therefore two matrices that should be equivalent according to the math, might not have strictly equivalent elements. For these situations, use transform.almostEqual instead of the strict transform.equal.
Parameters:
tr
ts
tolerance
- optional number, default to nudged.tolerance.
- Set to
0
for strict comparison.
Return:
- a boolean. True if the transforms are equal or almost equal.
For the difference metric, we use a modified L1 norm that values a, b, x, and y equally. If the sum of the differences is smaller or equal to the tolerance, consider the transforms equal.
Multiply the transform tr from the right with the given transform ts. In other words, the resulting transform is equivalent to first transforming with ts and then with tr. To put it short, transform the image of ts by tr.
Parameters:
Return:
Create a transform object.
Parameters:
a
- number. Indices m11 & m22.
- The diagonal of the linear transformation
b
- number. Indices m12 & -m21.
- The upper and lower triangle of the linear transformation.
x
- number. Index m31.
- The translation towards x.
y
- number. Index m32.
- The translation towards y
Return:
- a transform object
Are transforms equal? Tests that the elements of the transforms are strictly equal. For loose equality see almostEqual.
Parameters:
Return:
- a boolean
Convert a transform represented as an 4-element array
to a transform object { a, b, x, y }
.
Compatible with nudged.transform.toArray.
Parameters:
arrtr
- an array with four number elements
[a, b, x, y]
- an array with four number elements
Return:
Example:
> nudged.transform.fromArray([1, 2, 3, 4])
{ a: 1, b: 2, x: 3, y: 4 }
Create a nudged.transform object by using scale and rotation in respect of a center point.
Parameters:
center
- a point
scale
- a positive number. The scaling factor.
rotation
- a number. Rotation in radians from positive x axis towards pos. y axis.
Return:
Example:
> const tr = nudged.transform.fromPolar({ x: 4, y: 2 }, 2, 0)
> const p = { x: 2, y: 1 }
> nudged.point.transform(p, tr)
{ x: 0, y: 0 }
Create a transform that rotates around the center by the radians.
Parameters:
center
- a point
radians
- a number, angle
Return:
Example:
> let rot = nudged.transform.fromRotation({ x: 4, y: 2 }, Math.PI / 5)
> rot
{ a: 0.809..., b: 0.587..., x: 1.939..., y: -1.969... }
Create a transform that scales in respect of the center point and the scale multiplier. Such transform is called a homothety.
Parameters:
center
- a point
multiplier
- a number
Return:
Example:
> let x2 = nudged.transform.fromScale({ x: 4, y: 2 }, 2)
> x2
{ a: 2, b: 0, x: -4, y: -2 }
Create a transform from a string that uses the CSS transform matrix syntax: 'matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)'
Together with nudged.transform.toString this method makes an easy serialization and deserialization to and from strings.
Note that the function does not yet support other CSS transform functions such as 'translate' or 'perspective'. It might also give unexpected results if the matrix exhibits shear or non-uniform scaling.
Parameters:
str
- a string, the CSS matrix description
Return:
Throws if no valid transform is found
Create a transform that translates { 0, 0 }
to the point { x, y }
Parameters:
p
- a point
Return:
- a point
Example:
> let tl = nudged.transform.fromTranslation({ x: 4, y: 2 })
> tl
{ a: 1, b: 0, x: 4, y: 2 }
Get rotation of the transform in radians. The rotation is measured from the positive x-axis towards the positive y-axis.
Parameters:
tr
Return:
- a number, an angle in radians
Example:
> const t = nudged.transform.ROT180
> nudged.transform.getRotation(t)
3.1415...
Get the scale multiplier of the transformation.
Parameters:
tr
Return:
- a number, the scaling factor
Example:
> const t = nudged.transform.HALF
> nudged.transform.getScale(t)
0.5
Get the translating component of the given transform
as a vector { x, y }
.
Parameters:
tr
Return:
- a point
Example:
> const t = nudged.transform.ROT45
> nudged.transform.getTranslation(t)
{ x: 0, y: 0 }
Alias of nudged.transform.compose
.
Compute inversed transform. In other words, find transform X so that TX = XT = I, where T is the given transform.
Parameters:
tr
- a transform to be inverted
Throws if the given transformation is singular and cannot be inverted. This can occur for example in situations where the scale of the transform has dropped to zero.
Return:
Rotate image of the transform by the given radians so that the given center point stays fixed.
Parameters:
Return:
Rotate image of the transform to the given angle so that the given center point stays fixed.
Parameters:
Return:
Scale image of the transform by the given multiplier so that the given center point stays fixed. The operation is also called homothety.
Parameters:
Return:
Scale the transform tr so that
- its scale multiplier becomes equal with the given scale.
- its image stays fixed at the given center point
Parameters:
Return:
Represent the transform as a 4-element array. This the array is compatible with nudged.transform.fromArray.
Parameters:
tr
Return:
- an array
[a, b, x, y]
Get the similarity transformation matrix in the format common to other APIs, including:
Parameters:
tr
Return:
-
an object
{ a, b, c, d, e, g }
that represents the matrix below.┌ ┐ │ a c e │ │ b d f │ │ 0 0 1 │ └ ┘
Example:
> nudged.transform.toMatrix(tr)
{ a: 0.48, c: -0.52, e: 205.04,
b: 0.52, d: 0.48, f: 4.83 }
Return a string of CSS transform-function data type.
Together with nudged.transform.fromString, this method allows serialization to and from strings.
Example:
> let sc = nudged.transform.fromScale({ x: 4, y: 2 }, 2)
> nudged.transform.toString(sc)
'matrix(2.00000000,0.00000000,0.00000000,2.00000000,-4.00000000,-2.00000000)'
The matrix values are fixed to 8 decimals. This prevents bugs caused by the scientific notation e.g. '1e-12'. The default JavaScript number-to-string conversion might produce scientific notation with some very large and very small numbers. The scientific notation is not understood by all CSS parsers. We have experienced problems with Safari and Opera. Therefore toString must prevent the scientific notation here and convert to fixed number of decimal places. See SO for further details.
Modify transformation so that its image is translated by the given vector. Scale and rotation are kept intact. In other words the resulting transform first applies the given tr and applies an additional translation defined by the given vector.
Parameters:
tr
vec
- a vector
{ x, y }
- a vector
Return:
Modify transformation so that it maps { x: 0, y: 0 }
to the given point. The rotation and scale are kept intact.
Parameters:
Return:
Check if tr is valid, non-singular affine transformation.
Tools to measure how well the estimated transformations fit the data.
Compute mean squared error (MSE) that is the mean squared distances between the range points and transformed domain points.
Parameters:
tr
- an estimated transform
domain
- an array of points. The domain used in the estimation.
range
- an array of points. The range used in the estimation.
Return:
- a positive number
Get an array of residuals i.e. the distances between the range points and transformed domain points.
Parameters:
tr
- an estimated transform
domain
- an array of points. The domain used in the estimation.
range
- an array of points. The range used in the estimation.
Return:
- array of numbers, distances
Compute residual sum of squares (RSS) that is the sum of the squared distances between the range points and transformed domain points.
Parameters:
tr
- an estimated transform
domain
- an array of points. The domain used in the estimation.
range
- an array of points. The range used in the estimation.
Return:
- a positive number
Default tolerance to use when coping with floating point arithmetics. JavaScript floating point numbers have 52 bits in mantissa (IEEE-754). That is about 16 base10 digits. Therefore the tolerance should be much larger than 1 * 10^-16. Let say 1 * 10^-10 is a good one.
> nudged.tolerance
0.0000000001
Contains the module version string identical to the version in package.json. This feature is powered by genversion.
> nudged.version
'2.3.4'