├── index.js ├── examples ├── bounds │ ├── .gitignore │ └── webpack.config.js ├── cube │ ├── .gitignore │ └── webpack.config.js ├── spiral │ ├── .gitignore │ └── webpack.config.js └── tree │ ├── .gitignore │ ├── branch.png │ └── webpack.config.js ├── lib ├── version.js ├── rect2 │ ├── fitSize.js │ ├── create.js │ └── fitScale.js ├── poly2 │ ├── index.js │ └── create.js ├── circle3 │ ├── copy.js │ ├── area.js │ ├── atCenter.js │ ├── validate.js │ ├── equal.js │ ├── translate.js │ ├── size.js │ ├── almostEqual.js │ ├── transitTo.js │ ├── transitFrom.js │ ├── create.js │ └── offset.js ├── plane2 │ ├── copy.js │ ├── validate.js │ ├── compose.js │ ├── equal.js │ ├── getScale.js │ ├── almostEqual.js │ └── translateTo.js ├── plane3 │ ├── copy.js │ ├── validate.js │ ├── invert.js │ ├── getScale.js │ ├── equal.js │ ├── orientation.js │ ├── almostEqual.js │ └── getNormal.js ├── point3 │ ├── create.js │ ├── copy.js │ ├── average.js │ ├── fromArray.js │ ├── equal.js │ ├── toArray.js │ ├── round.js │ ├── almostEqual.js │ ├── distanceToPlane.js │ ├── translate.js │ └── distance.js ├── angle │ ├── index.js │ ├── degToRad.js │ └── radToDeg.js ├── sphere2 │ ├── area.js │ ├── copy.js │ ├── create.js │ ├── atCenter.js │ ├── size.js │ ├── equal.js │ └── translate.js ├── vec2 │ ├── copy.js │ ├── toArray.js │ ├── equal.js │ ├── magnitude.js │ ├── fromArray.js │ ├── dot.js │ ├── add.js │ ├── max.js │ ├── min.js │ ├── create.js │ ├── difference.js │ ├── invert.js │ ├── transformBy.js │ ├── cross.js │ ├── fromPolar.js │ ├── validate.js │ ├── scaleBy.js │ ├── rotateBy.js │ └── rotateTo.js ├── point2 │ ├── copy.js │ ├── toArray.js │ ├── fromArray.js │ ├── create.js │ ├── equal.js │ ├── transform.js │ ├── distance.js │ ├── almostEqual.js │ ├── difference.js │ ├── translate.js │ └── offset.js ├── vec3 │ ├── toArray.js │ ├── create.js │ ├── copy.js │ ├── add.js │ ├── invert.js │ ├── magnitude.js │ ├── dot.js │ └── equal.js ├── dir2 │ ├── copy.js │ ├── equal.js │ ├── fromPolar.js │ ├── toPolar.js │ ├── toVector.js │ ├── projectToPlane.js │ └── almostEqual.js ├── sphere3 │ ├── area.js │ ├── atCenter.js │ ├── copy.js │ ├── volume.js │ ├── create.js │ ├── size.js │ ├── equal.js │ └── translate.js ├── dist2 │ ├── equal.js │ ├── create.js │ ├── almostEqual.js │ ├── transitFrom.js │ └── transitTo.js ├── dist3 │ ├── create.js │ ├── equal.js │ ├── validate.js │ ├── almostEqual.js │ └── transitTo.js ├── scalar2 │ ├── equal.js │ ├── validate.js │ ├── create.js │ └── almostEqual.js ├── dir3 │ ├── copy.js │ ├── equal.js │ └── almostEqual.js ├── path2 │ ├── combine.js │ ├── create.js │ ├── index.js │ └── validate.js ├── path3 │ ├── combine.js │ ├── create.js │ └── validate.js ├── box3 │ ├── getAngle.js │ ├── getSize.js │ ├── getVolume.js │ └── getBasis.js ├── scalar3 │ ├── equal.js │ ├── validate.js │ ├── create.js │ └── almostEqual.js ├── size2 │ ├── area.js │ ├── create.js │ ├── atNorm.js │ ├── equal.js │ └── scaleBy.js ├── quat4 │ ├── norm.js │ ├── conjugate.js │ ├── create.js │ ├── fromVector.js │ ├── add.js │ └── difference.js ├── ray3 │ ├── getVector.js │ ├── copy.js │ ├── getOrigin.js │ ├── invert.js │ └── equal.js ├── vec4 │ ├── norm.js │ ├── create.js │ ├── equal.js │ ├── add.js │ ├── scaleBy.js │ └── index.js ├── helm3 │ ├── getDilation.js │ ├── copy.js │ ├── getTranslation.js │ ├── getRotation.js │ ├── toArray.js │ ├── fromArray.js │ ├── fromVector.js │ └── setTranslation.js ├── helm2 │ ├── getRotation.js │ ├── copy.js │ ├── getTranslation.js │ ├── toArray.js │ ├── getDilation.js │ ├── fromVector.js │ ├── fromArray.js │ ├── setTranslation.js │ └── solveLeft.js ├── segment2 │ ├── create.js │ ├── index.js │ └── validate.js ├── segment3 │ ├── create.js │ ├── toVector.js │ ├── index.js │ └── validate.js ├── scalar1 │ ├── equal.js │ ├── validate.js │ └── create.js ├── size3 │ ├── volume.js │ ├── equal.js │ ├── create.js │ ├── scaleBy.js │ └── atNorm.js ├── box2 │ ├── getSize.js │ ├── getArea.js │ ├── getAngle.js │ ├── offset.js │ ├── getPath.js │ └── translate.js ├── orient2 │ ├── equal.js │ ├── create.js │ └── index.js ├── rect3 │ └── create.js ├── line3 │ ├── index.js │ └── fromPoints.js ├── rot2 │ ├── create.js │ └── index.js ├── line2 │ ├── index.js │ ├── fromPoints.js │ └── normal.js └── epsilon.js ├── docs ├── geometry_angle.png ├── geometry_point.png ├── geometry_basis_2d.png ├── geometry_vector.png ├── projection_distance_2d.png ├── origin-dependent-sum-2d.png ├── origin-dependent-sum-3d.jpg ├── affineplane-social-banner.jpg ├── coordinates-directions-3d.png ├── projection-perspective-3d.png ├── geometry-helmert-transform-2d.png ├── projection-between-planes-point-2d.png └── projection-between-planes-vector-2d.png ├── .npmignore ├── .editorconfig └── test ├── version └── index.test.js ├── helm3 ├── getRotation.test.js ├── create.test.js ├── fromArray.test.js ├── getDilation.test.js ├── getTranslation.test.js ├── copy.test.js ├── toArray.test.js └── transitFrom.test.js ├── helm2 ├── copy.test.js ├── fromArray.test.js ├── create.test.js ├── getTranslation.test.js ├── toArray.test.js └── toMatrix.test.js ├── scalar2 ├── create.test.js ├── equal.test.js ├── validate.test.js └── almostEqual.test.js ├── scalar3 ├── create.test.js ├── equal.test.js ├── validate.test.js ├── almostEqual.test.js └── index.test.js ├── vec3 ├── invert.test.js ├── magnitude.test.js ├── rotateBy.test.js ├── rotateTo.test.js ├── sum.test.js ├── fromPolar.test.js ├── fromSpherical.test.js └── equal.test.js ├── point3 ├── distance.test.js ├── offset.test.js ├── difference.test.js ├── copy.test.js ├── average.test.js ├── almostEqual.test.js ├── toArray.test.js ├── fromArray.test.js ├── round.test.js └── equal.test.js ├── orient2 ├── create.test.js ├── index.test.js └── fromPolar.test.js ├── plane3 ├── getNormal.test.js ├── create.test.js ├── validate.test.js ├── compose.test.js ├── invert.test.js ├── difference.test.js ├── getScale.test.js ├── orientation.test.js ├── transitFrom.test.js ├── copy.test.js ├── almostEqual.test.js └── limitScale.test.js ├── point2 ├── difference.test.js ├── transitTo.test.js ├── transitFrom.test.js ├── almostEqual.test.js ├── direction.test.js └── offset.test.js ├── rot2 ├── index.test.js └── create.test.js ├── dir2 ├── toVector.test.js ├── projectToPlane.test.js ├── copy.test.js ├── toPolar.test.js └── fromVector.test.js ├── vec2 ├── create.test.js ├── transitTo.test.js ├── copy.test.js ├── magnitude.test.js ├── fromPolar.test.js ├── dot.test.js ├── inverse.test.js ├── unit.test.js └── equal.test.js ├── dist2 ├── create.test.js └── equal.test.js ├── dist3 ├── create.test.js ├── validate.test.js ├── projectToPlane.test.js ├── almostEqual.test.js └── index.test.js ├── ray3 ├── offset.test.js ├── getOrigin.test.js ├── getVector.test.js ├── copy.test.js ├── create.test.js ├── invert.test.js └── at.test.js ├── circle3 ├── positions.test.js └── almostEqual.test.js ├── sphere2 ├── transitTo.test.js ├── fromPoints.test.js ├── almostEqual.test.js ├── collide.test.js ├── atCenter.test.js ├── size.test.js ├── offset.test.js └── polarOffset.test.js ├── quat4 ├── norm.test.js ├── fromVector.test.js ├── conjugate.test.js ├── add.test.js ├── difference.test.js └── hamilton.test.js ├── angle ├── index.test.js ├── modulo.test.js ├── degToRad.test.js └── radToDeg.test.js ├── plane2 ├── create.test.js ├── fromFeatures.test.js ├── validate.test.js ├── compose.test.js ├── getScale.test.js ├── invert.test.js ├── difference.test.js ├── transitFrom.test.js ├── copy.test.js ├── almostEqual.test.js └── limitScale.test.js ├── sphere3 ├── transitTo.test.js ├── fromPoints.test.js ├── almostEqual.test.js ├── atCenter.test.js ├── size.test.js ├── volume.test.js └── offset.test.js ├── epsilon └── index.test.js ├── line2 ├── at.test.js ├── normal.test.js ├── fromPoints.test.js ├── index.test.js └── create.test.js ├── box2 ├── offset.test.js ├── translate.test.js ├── create.test.js ├── almostEqual.test.js └── getAngle.test.js ├── box3 ├── getAngle.test.js ├── offset.test.js ├── create.test.js ├── translate.test.js └── almostEqual.test.js ├── segment2 ├── create.test.js ├── index.test.js ├── transitTo.test.js └── transitFrom.test.js ├── path2 ├── create.test.js ├── combine.test.js ├── index.test.js ├── transitTo.test.js └── transitFrom.test.js ├── segment3 ├── conversions.test.js ├── create.test.js └── index.test.js ├── vec4 └── index.test.js ├── scalar1 ├── equal.test.js └── create.test.js ├── utils ├── transformEqual.js ├── almostEqual.js └── notAlmostEqual.js ├── line3 ├── at.test.js ├── fromPoints.test.js ├── index.test.js └── create.test.js ├── path3 ├── create.test.js ├── combine.test.js └── index.test.js ├── size3 ├── volume.test.js ├── create.test.js ├── scaleBy.test.js └── atNorm.test.js ├── rect2 ├── create.test.js └── index.test.js ├── rect3 ├── create.test.js └── index.test.js ├── size2 ├── create.test.js ├── scaleBy.test.js └── index.test.js └── dir3 ├── copy.test.js └── toVector.test.js /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib') 2 | -------------------------------------------------------------------------------- /examples/bounds/.gitignore: -------------------------------------------------------------------------------- 1 | app.bundle.js 2 | app.bundle.js.map 3 | -------------------------------------------------------------------------------- /examples/cube/.gitignore: -------------------------------------------------------------------------------- 1 | app.bundle.js 2 | app.bundle.js.map 3 | -------------------------------------------------------------------------------- /examples/spiral/.gitignore: -------------------------------------------------------------------------------- 1 | app.bundle.js 2 | app.bundle.js.map 3 | -------------------------------------------------------------------------------- /examples/tree/.gitignore: -------------------------------------------------------------------------------- 1 | app.bundle.js 2 | app.bundle.js.map 3 | -------------------------------------------------------------------------------- /lib/version.js: -------------------------------------------------------------------------------- 1 | // Generated by genversion. 2 | module.exports = '2.21.0' 3 | -------------------------------------------------------------------------------- /docs/geometry_angle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/geometry_angle.png -------------------------------------------------------------------------------- /docs/geometry_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/geometry_point.png -------------------------------------------------------------------------------- /docs/geometry_basis_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/geometry_basis_2d.png -------------------------------------------------------------------------------- /docs/geometry_vector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/geometry_vector.png -------------------------------------------------------------------------------- /examples/tree/branch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/examples/tree/branch.png -------------------------------------------------------------------------------- /docs/projection_distance_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/projection_distance_2d.png -------------------------------------------------------------------------------- /docs/origin-dependent-sum-2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/origin-dependent-sum-2d.png -------------------------------------------------------------------------------- /docs/origin-dependent-sum-3d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/origin-dependent-sum-3d.jpg -------------------------------------------------------------------------------- /docs/affineplane-social-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/affineplane-social-banner.jpg -------------------------------------------------------------------------------- /docs/coordinates-directions-3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/coordinates-directions-3d.png -------------------------------------------------------------------------------- /docs/projection-perspective-3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/projection-perspective-3d.png -------------------------------------------------------------------------------- /docs/geometry-helmert-transform-2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/geometry-helmert-transform-2d.png -------------------------------------------------------------------------------- /docs/projection-between-planes-point-2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/projection-between-planes-point-2d.png -------------------------------------------------------------------------------- /docs/projection-between-planes-vector-2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axelpale/affineplane/HEAD/docs/projection-between-planes-vector-2d.png -------------------------------------------------------------------------------- /lib/rect2/fitSize.js: -------------------------------------------------------------------------------- 1 | module.exports = (rect, target) => { 2 | // TODO 3 | // 4 | // Change size properties to cover the target area. 5 | // 6 | } 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .travis.yml 2 | .editorconfig 3 | .github 4 | 5 | /dist/.gitkeep 6 | /docs 7 | /examples 8 | /test 9 | 10 | .DS_Store 11 | .gitignore 12 | package-lock.json 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,yml,css,html,md}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /lib/poly2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.poly2 2 | // 3 | // A two-dimensional polygon; Array of point2; 4 | // A closed sequence of points `[{ x, y }, { x, y }, ...]`. 5 | // 6 | exports.create = require('./create') 7 | -------------------------------------------------------------------------------- /test/version/index.test.js: -------------------------------------------------------------------------------- 1 | const pjson = require('../../package.json') 2 | const unit = require('../../index') 3 | 4 | module.exports = (t) => { 5 | t.equal(unit.version, pjson.version, 'version match') 6 | t.end() 7 | } 8 | -------------------------------------------------------------------------------- /lib/circle3/copy.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.copy(c) 2 | // 3 | // Copy a circle object. 4 | // 5 | // Parameters 6 | // c 7 | // a circle3 8 | // 9 | // Return 10 | // a circle3 11 | // 12 | module.exports = require('../sphere3/copy') 13 | -------------------------------------------------------------------------------- /lib/plane2/copy.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane2.copy(plane) 2 | // 3 | // Clone the plane object. 4 | // 5 | // Parameters: 6 | // plane 7 | // a plane2 8 | // 9 | // Return: 10 | // a plane2 11 | // 12 | module.exports = require('../helm2/copy') 13 | -------------------------------------------------------------------------------- /lib/plane3/copy.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.copy(plane) 2 | // 3 | // Clone the plane object. 4 | // 5 | // Parameters: 6 | // plane 7 | // a plane3 8 | // 9 | // Return: 10 | // a plane3 11 | // 12 | module.exports = require('../helm3/copy') 13 | -------------------------------------------------------------------------------- /lib/point3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, z) => { 2 | // @affineplane.point3.create(x, y, z) 3 | // 4 | // Create a three-dimensional point `{x, y, z}`. 5 | // 6 | // Return 7 | // a point3 8 | // 9 | return { x, y, z } 10 | } 11 | -------------------------------------------------------------------------------- /lib/circle3/area.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.area(c) 2 | // 3 | // Get area of the circle. 4 | // 5 | // Parameters: 6 | // a circle3 7 | // 8 | // Return 9 | // a scalar2, a number representing area 10 | // 11 | module.exports = require('../sphere2/area') 12 | -------------------------------------------------------------------------------- /lib/point3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.point3.copy(p) 3 | // 4 | // Clone point3 to a new object. 5 | // 6 | // Return 7 | // a point3 8 | // 9 | return { 10 | x: p.x, 11 | y: p.y, 12 | z: p.z 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/helm3/getRotation.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../index').helm3 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic rotations', (t) => { 5 | t.almostEqual(helm3.getRotation(helm3.ROT90), Math.PI / 2) 6 | 7 | t.end() 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /examples/cube/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './app.js', 3 | output: { 4 | filename: 'app.bundle.js', 5 | path: __dirname, 6 | sourceMapFilename: '[file].map' 7 | }, 8 | 9 | devtool: 'source-map', 10 | 11 | mode: 'production' 12 | } 13 | -------------------------------------------------------------------------------- /lib/plane2/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane2.validate(plane) 2 | // 3 | // Check if object is a valid plane2. 4 | // 5 | // Parameters: 6 | // plane 7 | // an object 8 | // 9 | // Return 10 | // a boolean 11 | // 12 | module.exports = require('../helm2/validate') 13 | -------------------------------------------------------------------------------- /lib/plane3/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.validate(plane) 2 | // 3 | // Check if object is a valid plane3. 4 | // 5 | // Parameters: 6 | // plane 7 | // an object 8 | // 9 | // Return 10 | // a boolean 11 | // 12 | module.exports = require('../helm3/validate') 13 | -------------------------------------------------------------------------------- /lib/rect2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (basis, size) => { 2 | // Parameters: 3 | // basis 4 | // a plane2 5 | // size 6 | // a size2 7 | // 8 | console.warn('affineplane.rect2 is deprecated. Use box2 instead.') 9 | return { basis, size } 10 | } 11 | -------------------------------------------------------------------------------- /examples/bounds/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './app.js', 3 | output: { 4 | filename: 'app.bundle.js', 5 | path: __dirname, 6 | sourceMapFilename: '[file].map' 7 | }, 8 | 9 | devtool: 'source-map', 10 | 11 | mode: 'production' 12 | } 13 | -------------------------------------------------------------------------------- /examples/spiral/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './app.js', 3 | output: { 4 | filename: 'app.bundle.js', 5 | path: __dirname, 6 | sourceMapFilename: '[file].map' 7 | }, 8 | 9 | devtool: 'source-map', 10 | 11 | mode: 'production' 12 | } 13 | -------------------------------------------------------------------------------- /lib/angle/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.angle 2 | // 3 | // Common utilites to handle angles. 4 | // 5 | // ![Angle](geometry_angle.png) 6 | // 7 | 8 | exports.modulo = require('./modulo') 9 | exports.degToRad = require('./degToRad') 10 | exports.radToDeg = require('./radToDeg') 11 | -------------------------------------------------------------------------------- /lib/point3/average.js: -------------------------------------------------------------------------------- 1 | // @affineplane.point3.average(ps) 2 | // @affineplane.point3.mean 3 | // 4 | // Average of points. 5 | // 6 | // Parameters 7 | // ps 8 | // array of point3 9 | // 10 | // Return 11 | // a point3 12 | // 13 | module.exports = require('../vec3/average') 14 | -------------------------------------------------------------------------------- /test/helm2/copy.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: ensure different identity', (t) => { 5 | const tr = { a: 1, b: 0, x: 0, y: 0 } 6 | t.notEqual(helm2.copy(tr), tr) 7 | 8 | t.end() 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /lib/point3/fromArray.js: -------------------------------------------------------------------------------- 1 | // @affineplane.point3.fromArray(arrp) 2 | // 3 | // Create a point3 from array `[x, y, z]`. 4 | // 5 | // Parameters: 6 | // arrp 7 | // a three-element array 8 | // 9 | // Return 10 | // a point3 11 | // 12 | module.exports = require('../vec3/fromArray') 13 | -------------------------------------------------------------------------------- /lib/sphere2/area.js: -------------------------------------------------------------------------------- 1 | module.exports = (sp) => { 2 | // @affineplane.sphere2.area(sp) 3 | // 4 | // Get area of the sphere. 5 | // 6 | // Parameters: 7 | // a sphere2 8 | // 9 | // Return 10 | // a scalar2, a number 11 | // 12 | return sp.r * sp.r * Math.PI 13 | } 14 | -------------------------------------------------------------------------------- /test/scalar2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar2 = affineplane.scalar2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.equal(scalar2.create(-3), -3, 'should allow negative value') 7 | 8 | t.end() 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /test/scalar3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar3 = affineplane.scalar3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.equal(scalar3.create(-3), -3, 'should allow negative value') 7 | 8 | t.end() 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /test/vec3/invert.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic inverse', (t) => { 5 | t.deepEqual( 6 | vec3.invert({ x: 1, y: 2, z: 3 }), 7 | { x: -1, y: -2, z: -3 } 8 | ) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/vec3/magnitude.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic magnitude', (t) => { 5 | t.equal(vec3.magnitude({ x: 3, y: 4, z: 12 }), 13) 6 | t.equal(vec3.norm({ x: 3, y: 4, z: 0 }), 5) 7 | t.end() 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /lib/vec2/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec2.copy(v) 3 | // 4 | // Copy vector object. 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // 10 | // Return 11 | // a vec2 12 | // 13 | return { 14 | x: v.x, 15 | y: v.y 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/vec2/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec2.toArray(v) 3 | // 4 | // Get the vector object as an array. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec2 9 | // 10 | // Return 11 | // an array `[x, y]` 12 | // 13 | return [v.x, v.y] 14 | } 15 | -------------------------------------------------------------------------------- /test/helm3/create.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../lib/helm3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic create', (t) => { 5 | t.deepEqual( 6 | helm3.create(1, 2, 3, 4, 5), 7 | { a: 1, b: 2, x: 3, y: 4, z: 5 } 8 | ) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/plane3/invert.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.invert(plane) 2 | // 3 | // Parameters: 4 | // plane 5 | // a plane3, represented on the reference plane. 6 | // 7 | // Return 8 | // a plane3, the reference plane represented on the given plane. 9 | // 10 | module.exports = require('../helm3/invert') 11 | -------------------------------------------------------------------------------- /lib/point2/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.point2.copy(p) 3 | // 4 | // Copy point object. 5 | // 6 | // Parameters 7 | // p 8 | // a point2 9 | // 10 | // Return 11 | // a point2 12 | // 13 | return { 14 | x: p.x, 15 | y: p.y 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/point2/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.point2.toArray(p) 3 | // 4 | // Get the point2 object as an array. 5 | // 6 | // Parameters: 7 | // p 8 | // a point2 9 | // 10 | // Return 11 | // an array [x, y] 12 | // 13 | return [p.x, p.y] 14 | } 15 | -------------------------------------------------------------------------------- /lib/vec3/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec3.toArray(v) 3 | // 4 | // Convert vector to array with elements `[x, y, z]`. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec3 9 | // 10 | // Return 11 | // an array 12 | // 13 | return [v.x, v.y, v.z] 14 | } 15 | -------------------------------------------------------------------------------- /test/point3/distance.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic distance', (t) => { 5 | t.equal(point3.distance( 6 | { x: 0, y: 0, z: 0 }, 7 | { x: 3, y: 4, z: 12 } 8 | ), 13) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/point3/offset.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic offset', (t) => { 5 | t.deepEqual(point3.offset( 6 | { x: 0, y: 0, z: 0 }, 7 | 1, 1, 1 8 | ), { x: 1, y: 1, z: 1 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/dir2/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (dir) => { 2 | // @affineplane.dir2.copy(dir) 3 | // 4 | // Copy direction object. 5 | // 6 | // Parameters 7 | // dir 8 | // a dir2 9 | // 10 | // Return 11 | // a dir2 12 | // 13 | return { 14 | x: dir.x, 15 | y: dir.y 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/sphere3/area.js: -------------------------------------------------------------------------------- 1 | module.exports = (sp) => { 2 | // @affineplane.sphere3.area(sp) 3 | // 4 | // Get surface area of the sphere. 5 | // 6 | // Parameters: 7 | // a sphere3 8 | // 9 | // Return 10 | // a scalar2, a number. The area. 11 | // 12 | return sp.r * sp.r * Math.PI * 4 13 | } 14 | -------------------------------------------------------------------------------- /test/helm2/fromArray.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: happy', (t) => { 5 | t.deepEqual(helm2.fromArray([1, 2, 3, 4]), { 6 | a: 1, 7 | b: 2, 8 | x: 3, 9 | y: 4 10 | }) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/dist2/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist2.equal(c, d) 2 | // 3 | // Test if distances c, d are strictly equal. 4 | // 5 | // Parameters 6 | // c 7 | // a number, the dist2 8 | // d 9 | // a number, the dist2 10 | // 11 | // Return 12 | // a boolean 13 | // 14 | module.exports = require('../scalar1/equal') 15 | -------------------------------------------------------------------------------- /lib/dist3/create.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist3.create(d) 2 | // 3 | // Create a measure. Basically it is just the absolute value of the number. 4 | // 5 | // Parameters 6 | // d 7 | // a number 8 | // 9 | // Return 10 | // a number, always zero or positive. 11 | // 12 | module.exports = require('../dist2/create') 13 | -------------------------------------------------------------------------------- /lib/dist3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist3.equal(c, d) 2 | // 3 | // Test if distances c, d are strictly equal. 4 | // 5 | // Parameters 6 | // c 7 | // a number, the dist3 8 | // d 9 | // a number, the dist3 10 | // 11 | // Return 12 | // a boolean 13 | // 14 | module.exports = require('../scalar1/equal') 15 | -------------------------------------------------------------------------------- /lib/vec3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, z) => { 2 | // @affineplane.vec3.create(x, y, z) 3 | // 4 | // Parameters: 5 | // x 6 | // a number 7 | // y 8 | // a number 9 | // z 10 | // a number 11 | // 12 | // Return 13 | // a vec3 14 | // 15 | return { x, y, z } 16 | } 17 | -------------------------------------------------------------------------------- /test/orient2/create.test.js: -------------------------------------------------------------------------------- 1 | const orient2 = require('../../index').orient2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic create', (t) => { 5 | t.deepEqual( 6 | orient2.create(1, 0), 7 | { a: 1, b: 0 }, 8 | 'create orient2 object' 9 | ) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/plane3/getNormal.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic normal', (t) => { 5 | t.almostEqual( 6 | plane3.getNormal({}), 7 | { x: 0, y: 0, z: 1 }, 8 | 'any input goes' 9 | ) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/point2/difference.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic difference', (t) => { 5 | t.deepEqual(point2.difference( 6 | { x: 3, y: 0 }, 7 | { x: 0, y: 3 } 8 | ), { x: -3, y: 3 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/scalar2/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar2.equal(c, d) 2 | // 3 | // Test if scalars c, d are strictly equal. 4 | // 5 | // Parameters 6 | // c 7 | // a number, a scalar2 8 | // d 9 | // a number, a scalar2 10 | // 11 | // Return 12 | // a boolean 13 | // 14 | module.exports = require('../scalar1/equal') 15 | -------------------------------------------------------------------------------- /lib/vec3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec3.copy(v) 3 | // 4 | // Clone the vector object. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec3 9 | // 10 | // Return 11 | // a vec3 12 | // 13 | return { 14 | x: v.x, 15 | y: v.y, 16 | z: v.z 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/rot2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | create: require('./create.test'), 4 | validate: require('./validate.test') 5 | } 6 | 7 | module.exports = (t) => { 8 | Object.keys(units).forEach((unitName) => { 9 | t.test('affineplane.rot2.' + unitName, units[unitName]) 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /lib/dir3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (dir) => { 2 | // @affineplane.dir3.copy(dir) 3 | // 4 | // Copy direction object. 5 | // 6 | // Parameters 7 | // dir 8 | // a dir3 9 | // 10 | // Return 11 | // a dir3 12 | // 13 | return { 14 | x: dir.x, 15 | y: dir.y, 16 | z: dir.z 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/sphere2/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.sphere2.copy(p) 3 | // 4 | // Copy a sphere object. 5 | // 6 | // Parameters 7 | // p 8 | // a sphere2 9 | // 10 | // Return 11 | // a sphere2 12 | // 13 | return { 14 | x: p.x, 15 | y: p.y, 16 | r: p.r 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/dir2/toVector.test.js: -------------------------------------------------------------------------------- 1 | const dir2 = require('../../lib/dir2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic dir from vector', (t) => { 5 | t.almostEqual( 6 | dir2.toVector({ x: 0, y: 1 }, 2), 7 | { x: 0, y: 2 }, 8 | 'with magnitude' 9 | ) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/helm2/create.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: happy', (t) => { 5 | t.deepEqual(helm2.create(1, 2, 3, 4), { 6 | a: 1, 7 | b: 2, 8 | x: 3, 9 | y: 4 10 | }, 'create helm2 object') 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/helm2/getTranslation.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic', (t) => { 5 | const tr = { a: 1, b: 2, x: 3, y: 4 } 6 | t.deepEqual(helm2.getTranslation(tr), { 7 | x: 3, 8 | y: 4 9 | }) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/vec2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vector = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: happy', (t) => { 6 | t.deepEqual(vector.create(1, 2), { 7 | x: 1, 8 | y: 2 9 | }, 'create vector object') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/vec2/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const vec2 = require('../../lib/vec2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic transit to plane', (t) => { 5 | t.deepEqual(vec2.transitTo( 6 | { x: 20, y: 30 }, 7 | { a: 2, b: 0, x: 20, y: 30 } 8 | ), { x: 10, y: 15 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/path2/combine.js: -------------------------------------------------------------------------------- 1 | module.exports = (pa, pb) => { 2 | // @affineplane.path2.combine(pa, pb) 3 | // 4 | // Combine paths together. 5 | // 6 | // Parameters: 7 | // pa 8 | // a path2 9 | // pb 10 | // a path2 11 | // 12 | // Return 13 | // a path2 14 | // 15 | return pa.concat(pb) 16 | } 17 | -------------------------------------------------------------------------------- /lib/path3/combine.js: -------------------------------------------------------------------------------- 1 | module.exports = (pa, pb) => { 2 | // @affineplane.path3.combine(pa, pb) 3 | // 4 | // Combine paths together. 5 | // 6 | // Parameters: 7 | // pa 8 | // a path3 9 | // pb 10 | // a path3 11 | // 12 | // Return 13 | // a path3 14 | // 15 | return pa.concat(pb) 16 | } 17 | -------------------------------------------------------------------------------- /lib/vec3/add.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec3.add(v, w) 3 | // 4 | // Parameters: 5 | // v 6 | // a vec3 7 | // w 8 | // a vec3 9 | // 10 | // Return 11 | // a vec3 12 | // 13 | return { 14 | x: v.x + w.x, 15 | y: v.y + w.y, 16 | z: v.z + w.z 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/helm3/fromArray.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../index').helm3 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: happy', (t) => { 5 | t.deepEqual(helm3.fromArray([1, 2, 3, 4, 5]), { 6 | a: 1, 7 | b: 2, 8 | x: 3, 9 | y: 4, 10 | z: 5 11 | }) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/point2/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic transit to plane', (t) => { 5 | t.deepEqual(point2.transitTo( 6 | { x: 20, y: 30 }, 7 | { a: 1, b: 0, x: 20, y: 30 } 8 | ), { x: 0, y: 0 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/point3/difference.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic difference', (t) => { 5 | t.deepEqual(point3.difference( 6 | { x: 3, y: 0, z: 0 }, 7 | { x: 0, y: 0, z: 3 } 8 | ), { x: -3, y: 0, z: 3 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/scalar2/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar2 = affineplane.scalar2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.ok(scalar2.equal(1, 1), 'numbers equal') 7 | t.notOk(scalar2.equal(0, 1), 'numbers not equal') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/scalar3/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar3 = affineplane.scalar3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.ok(scalar3.equal(1, 1), 'numbers equal') 7 | t.notOk(scalar3.equal(0, 1), 'numbers not equal') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /lib/box3/getAngle.js: -------------------------------------------------------------------------------- 1 | // @affineplane.box3.getAngle(box) 2 | // 3 | // Compute box angle in radians with respect to the reference basis. 4 | // 5 | // Parameters 6 | // box 7 | // a box2, in the reference basis. 8 | // 9 | // Return 10 | // a number, the angle in radians. 11 | // 12 | module.exports = require('../box2/getAngle') 13 | -------------------------------------------------------------------------------- /lib/scalar3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar3.equal(c, d) 2 | // 3 | // Test if the third-order scalars c, d are strictly equal. 4 | // 5 | // Parameters 6 | // c 7 | // a number, a scalar2 8 | // d 9 | // a number, a scalar2 10 | // 11 | // Return 12 | // a boolean 13 | // 14 | module.exports = require('../scalar1/equal') 15 | -------------------------------------------------------------------------------- /lib/size2/area.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz) => { 2 | // @affineplane.size2.area(sz) 3 | // 4 | // Area. If your w and h are in px, this gives you 5 | // the total number of pixels. 6 | // 7 | // Parameters 8 | // sz 9 | // a size2 10 | // 11 | // Return 12 | // a number 13 | // 14 | return sz.w * sz.h 15 | } 16 | -------------------------------------------------------------------------------- /lib/vec2/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.equal(v, w) 3 | // 4 | // Test if vectors v,w are equal 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // w 10 | // a vec2 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | return v.x === w.x && v.y === w.y 16 | } 17 | -------------------------------------------------------------------------------- /lib/vec2/magnitude.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec2.magnitude(v) 3 | // @affineplane.vec2.norm 4 | // 5 | // The length of the vector. 6 | // 7 | // Parameters 8 | // v 9 | // a vec2 10 | // 11 | // Return 12 | // a number 13 | // 14 | return Math.sqrt(v.x * v.x + v.y * v.y) 15 | } 16 | -------------------------------------------------------------------------------- /test/dist2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dist2 = affineplane.dist2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | t.equal(dist2.create(-3), 3, 'should be absolute value') 7 | t.equal(dist2.create(0), 0, 'should allow zero') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/dist3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dist3 = affineplane.dist3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | t.equal(dist3.create(-3), 3, 'should be absolute value') 7 | t.equal(dist3.create(0), 0, 'should allow zero') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /lib/circle3/atCenter.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.atCenter(c) 2 | // 3 | // Get the center point of the circle. 4 | // Note that the circle3 object itself can act as a point3 in many cases. 5 | // 6 | // Parameters: 7 | // c 8 | // a circle3 9 | // 10 | // Return 11 | // a point3 12 | // 13 | module.exports = require('../point3/copy') 14 | -------------------------------------------------------------------------------- /lib/dist3/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist3.validate(d) 2 | // 3 | // Check if the argument is a valid dist3. 4 | // Valid dist3 is a zero or positive number and not NaN. 5 | // 6 | // Parameter 7 | // d 8 | // a value 9 | // 10 | // Return 11 | // a boolean, true if valid 12 | // 13 | module.exports = require('../dist2/validate') 14 | -------------------------------------------------------------------------------- /lib/point3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.point3.equal(p, q) 2 | // @affineplane.point3.equals 3 | // 4 | // Test if points p, q are equal in value. 5 | // 6 | // Parameters 7 | // p 8 | // a point3 9 | // q 10 | // a point3 11 | // 12 | // Return 13 | // a boolean, true if equal 14 | // 15 | module.exports = require('../vec3/equal') 16 | -------------------------------------------------------------------------------- /lib/quat4/norm.js: -------------------------------------------------------------------------------- 1 | module.exports = (q) => { 2 | // @affineplane.quat4.norm(q) 3 | // 4 | // The length of quaternion. Also called the norm. 5 | // 6 | // Parameters: 7 | // q 8 | // a quat4 9 | // 10 | // Return 11 | // a number 12 | // 13 | return Math.sqrt(q.a * q.a + q.b * q.b + q.c * q.c + q.d * q.d) 14 | } 15 | -------------------------------------------------------------------------------- /lib/ray3/getVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (r) => { 2 | // @affineplane.ray3.getVector(r) 3 | // 4 | // Get the spanning vector of the ray. 5 | // 6 | // Parameters 7 | // r 8 | // a ray3 9 | // 10 | // Return 11 | // a vec3 12 | // 13 | return { 14 | x: r.dx, 15 | y: r.dy, 16 | z: r.dz 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/scalar2/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar2.validate(s) 2 | // 3 | // Check if the argument is a valid scalar2. 4 | // Valid scalar2 is a number and not NaN. 5 | // 6 | // Parameter 7 | // s 8 | // a value 9 | // 10 | // Return 11 | // a boolean, true if valid scalar2 12 | // 13 | module.exports = require('../scalar1/validate') 14 | -------------------------------------------------------------------------------- /lib/scalar3/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar3.validate(s) 2 | // 3 | // Check if the argument is a valid scalar3. 4 | // Valid scalar3 is a number and not NaN. 5 | // 6 | // Parameter 7 | // s 8 | // a value 9 | // 10 | // Return 11 | // a boolean, true if valid scalar3 12 | // 13 | module.exports = require('../scalar1/validate') 14 | -------------------------------------------------------------------------------- /lib/sphere3/atCenter.js: -------------------------------------------------------------------------------- 1 | // @affineplane.sphere3.atCenter(sp) 2 | // 3 | // Get the center point of the sphere. 4 | // Note that the sphere3 object itself can act as a point3 in many cases. 5 | // 6 | // Parameters: 7 | // sp 8 | // a sphere3 9 | // 10 | // Return 11 | // a point3 12 | // 13 | module.exports = require('../point3/copy') 14 | -------------------------------------------------------------------------------- /lib/vec4/norm.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec4.norm(v) 3 | // 4 | // The length of 4D vector. Also called the norm. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec4 9 | // 10 | // Return 11 | // a number 12 | // 13 | return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w) 14 | } 15 | -------------------------------------------------------------------------------- /test/ray3/offset.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: ray3 offset', (t) => { 5 | t.deepEqual(ray3.offset( 6 | { x: 0, y: 0, z: 0, dx: 0, dy: 0, dz: 1 }, 7 | 1, 1, 1 8 | ), { x: 1, y: 1, z: 1, dx: 0, dy: 0, dz: 1 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/rot2/create.test.js: -------------------------------------------------------------------------------- 1 | const rot2 = require('../../index').rot2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic create', (t) => { 5 | t.deepEqual( 6 | rot2.create(1, 0), 7 | { 8 | a: 1, 9 | b: 0 10 | }, 11 | 'create rot2 object' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/vec2/copy.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vector = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: ensure different identity', (t) => { 6 | const vec = { x: 0, y: 0 } 7 | t.notEqual( 8 | vector.copy(vec), 9 | vec 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/dir2/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dir2.equal(d, dd) 2 | // 3 | // Test if directions are strictly equal in value. 4 | // The directions are compared as two vectors. 5 | // 6 | // Parameters 7 | // d 8 | // a dir2 9 | // dd 10 | // a dir2 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | module.exports = require('../vec2/equal') 16 | -------------------------------------------------------------------------------- /lib/dir3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dir3.equal(d, dd) 2 | // 3 | // Test if directions are strictly equal in value. 4 | // The directions are compared as two vectors. 5 | // 6 | // Parameters 7 | // d 8 | // a dir3 9 | // dd 10 | // a dir3 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | module.exports = require('../vec3/equal') 16 | -------------------------------------------------------------------------------- /lib/helm3/getDilation.js: -------------------------------------------------------------------------------- 1 | // @affineplane.helm3.getDilation(tr) 2 | // @affineplane.helm3.getScale 3 | // 4 | // Get the dilation component of the transformation. 5 | // 6 | // Parameters: 7 | // tr 8 | // a helm3 9 | // 10 | // Return: 11 | // a number, the scale multiplier. 12 | // 13 | module.exports = require('../helm2/getDilation') 14 | -------------------------------------------------------------------------------- /lib/sphere3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.sphere3.copy(p) 3 | // 4 | // Copy a sphere object. 5 | // 6 | // Parameters 7 | // p 8 | // a sphere3 9 | // 10 | // Return 11 | // a sphere3 12 | // 13 | return { 14 | x: p.x, 15 | y: p.y, 16 | z: p.z, 17 | r: p.r 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/circle3/positions.test.js: -------------------------------------------------------------------------------- 1 | const circle3 = require('../../lib/circle3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic atCenter', (t) => { 5 | t.deepEqual( 6 | circle3.atCenter({ x: 1, y: 1, z: 1, r: 1 }), 7 | { x: 1, y: 1, z: 1 }, 8 | 'should drop radius' 9 | ) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/helm3/getDilation.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../lib/helm3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic scalings', (t) => { 5 | t.equal(helm3.getDilation(helm3.IDENTITY), 1) 6 | t.equal(helm3.getDilation(helm3.HALF), 0.5) 7 | t.equal(helm3.getDilation(helm3.X2), 2) 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/helm3/getTranslation.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../index').helm3 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic', (t) => { 5 | const tr = { a: 1, b: 2, x: 3, y: 4, z: 5 } 6 | t.deepEqual(helm3.getTranslation(tr), { 7 | x: 3, 8 | y: 4, 9 | z: 5 10 | }) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /examples/tree/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | 4 | module.exports = { 5 | entry: './app.js', 6 | output: { 7 | filename: 'app.bundle.js', 8 | path: __dirname, 9 | sourceMapFilename: '[file].map', 10 | }, 11 | 12 | devtool: 'source-map', 13 | 14 | mode: 'production' 15 | } 16 | -------------------------------------------------------------------------------- /lib/helm2/getRotation.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm2.getRotation(tr) 3 | // 4 | // Get the rotation component of the transform in radians. 5 | // 6 | // Parameters: 7 | // tr 8 | // a helm2 9 | // 10 | // Return: 11 | // a number, in radians 12 | // 13 | return Math.atan2(tr.b, tr.a) 14 | } 15 | -------------------------------------------------------------------------------- /lib/segment2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (p0, p1) => { 2 | // @affineplane.segment2.create(p0, p1) 3 | // 4 | // Create a segment from points. 5 | // 6 | // Parameters: 7 | // p0 8 | // a point2 9 | // p1 10 | // a point2 11 | // 12 | // Return: 13 | // a segment2, an array. 14 | // 15 | return [p0, p1] 16 | } 17 | -------------------------------------------------------------------------------- /lib/segment3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (p0, p1) => { 2 | // @affineplane.segment3.create(p0, p1) 3 | // 4 | // Create a segment from points. 5 | // 6 | // Parameters: 7 | // p0 8 | // a point3 9 | // p1 10 | // a point3 11 | // 12 | // Return: 13 | // a segment3, an array. 14 | // 15 | return [p0, p1] 16 | } 17 | -------------------------------------------------------------------------------- /lib/sphere3/volume.js: -------------------------------------------------------------------------------- 1 | const alpha = 4 * Math.PI / 3 2 | 3 | module.exports = (sp) => { 4 | // @affineplane.sphere3.volume(sp) 5 | // 6 | // Get volume of the sphere. 7 | // 8 | // Parameters: 9 | // a sphere3 10 | // 11 | // Return 12 | // a scalar3, a number. The volume. 13 | // 14 | return alpha * sp.r * sp.r * sp.r 15 | } 16 | -------------------------------------------------------------------------------- /lib/vec2/fromArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (arrp) => { 2 | // @affineplane.vec2.fromArray(arrp) 3 | // 4 | // Create `{ x, y }` vector from array `[x, y]`. 5 | // 6 | // Parameters: 7 | // arrp 8 | // an array 9 | // 10 | // Return 11 | // a vec2 12 | // 13 | return { 14 | x: arrp[0], 15 | y: arrp[1] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/dist3/validate.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') // should be exported 2 | const dist3 = affineplane.dist3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.true(dist3.validate(1), 'one is valid') 7 | t.false(dist3.validate(-1), 'negative is not valid') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/helm3/copy.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../lib/helm3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic', (t) => { 5 | const h = { a: 1, b: 2, x: 3, y: 4, z: 5 } 6 | const hc = helm3.copy(h) 7 | t.deepEqual(h, hc, 'equal value') 8 | t.notEqual(h, hc, 'not strictly equal') 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/point3/copy.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: copy point3', (t) => { 5 | const p = { x: 1, y: 2, z: 5 } 6 | const c = point3.copy(p) 7 | 8 | t.deepEqual(p, c, 'same content') 9 | t.notEqual(p, c, 'not same object') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/scalar2/validate.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') // should be exported 2 | const scalar2 = affineplane.scalar2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.true(scalar2.validate(0), 'zero is valid') 7 | t.false(scalar2.validate(NaN), 'detect NaN') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/scalar3/validate.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') // should be exported 2 | const scalar2 = affineplane.scalar2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.true(scalar2.validate(0), 'zero is valid') 7 | t.false(scalar2.validate(NaN), 'detect NaN') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/sphere2/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic transit to plane', (t) => { 5 | t.deepEqual(sphere2.transitTo( 6 | { x: 20, y: 30, r: 40 }, 7 | { a: 1, b: 0, x: 20, y: 30 } 8 | ), { x: 0, y: 0, r: 40 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/vec3/invert.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec3.invert(v) 3 | // @affineplane.vec3.negate 4 | // 5 | // Get the vector -v. 6 | // 7 | // Parameters: 8 | // v 9 | // a vec3 10 | // 11 | // Return 12 | // a vec3 13 | // 14 | return { 15 | x: -v.x, 16 | y: -v.y, 17 | z: -v.z 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec3/magnitude.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec3.magnitude(v) 3 | // @affineplane.vec3.norm 4 | // 5 | // The euclidean length of the vector. 6 | // 7 | // Parameters 8 | // v 9 | // a vec3 10 | // 11 | // Return 12 | // a number 13 | // 14 | return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) 15 | } 16 | -------------------------------------------------------------------------------- /test/point3/average.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: average point3', (t) => { 5 | t.deepEqual(point3.average([ 6 | { x: 3, y: 0, z: 0 }, 7 | { x: 0, y: 3, z: 0 }, 8 | { x: 0, y: 0, z: 3 } 9 | ]), { x: 1, y: 1, z: 1 }) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/ray3/getOrigin.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: get ray3 origin', (t) => { 5 | const r = { x: 1, y: 2, z: 3, dx: 4, dy: 5, dz: 6 } 6 | const p = ray3.getOrigin(r) 7 | 8 | t.deepEqual(p, { x: 1, y: 2, z: 3 }, 'should be a point') 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/ray3/getVector.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: get ray3 vector', (t) => { 5 | const r = { x: 1, y: 2, z: 3, dx: 4, dy: 5, dz: 6 } 6 | const v = ray3.getVector(r) 7 | 8 | t.deepEqual(v, { x: 4, y: 5, z: 6 }, 'should be a vector') 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/vec3/rotateBy.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic rotation', (t) => { 6 | const v = { x: 1, y: 0, z: 0 } 7 | t.almostEqual( 8 | vec3.rotateBy(v, PI / 2, PI / 2), 9 | { x: 0, y: 0, z: 1 } 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/vec3/rotateTo.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic rotation', (t) => { 6 | const v = { x: 3, y: 4, z: 0 } 7 | t.almostEqual( 8 | vec3.rotateTo(v, PI / 2, PI / 2), 9 | { x: 0, y: 0, z: 5 } 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/circle3/validate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.validate(c) 2 | // 3 | // Check if the object is a valid circle3. 4 | // A valid circle3 has x, y, z, r properties that are valid numbers. 5 | // 6 | // Parameter 7 | // c 8 | // an object 9 | // 10 | // Return 11 | // a boolean, true if valid 12 | // 13 | module.exports = require('../sphere3/validate') 14 | -------------------------------------------------------------------------------- /lib/helm2/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (tr) => { 2 | // @affineplane.helm2.copy(tr) 3 | // @affineplane.helm2.clone 4 | // 5 | // Parameters 6 | // tr 7 | // a helm2, a transform 8 | // 9 | // Return 10 | // a helm2, a transform 11 | // 12 | return { 13 | a: tr.a, 14 | b: tr.b, 15 | x: tr.x, 16 | y: tr.y 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/quat4/conjugate.js: -------------------------------------------------------------------------------- 1 | module.exports = (q) => { 2 | // @affineplane.quat4.conjugate(q) 3 | // 4 | // Get the conjugate of a quaternion. 5 | // 6 | // Parameters: 7 | // q 8 | // a quat4 9 | // 10 | // Return 11 | // a quat4 12 | // 13 | return { 14 | a: q.a, 15 | b: -q.b, 16 | c: -q.c, 17 | d: -q.d 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/scalar1/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (c, d) => { 2 | // @affineplane.scalar1.equal(c, d) 3 | // 4 | // Test if scalars c, d are strictly equal. 5 | // 6 | // Parameters 7 | // c 8 | // a number, a scalar1 9 | // d 10 | // a number, a scalar1 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | return c === d 16 | } 17 | -------------------------------------------------------------------------------- /lib/size3/volume.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz) => { 2 | // @affineplane.size3.volume(sz) 3 | // 4 | // Volume. If your w, h, and d are in pixels, this gives you 5 | // the total number of voxels. 6 | // 7 | // Parameters 8 | // sz 9 | // a size3 10 | // 11 | // Return 12 | // a number 13 | // 14 | return sz.w * sz.h * sz.d 15 | } 16 | -------------------------------------------------------------------------------- /lib/vec4/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, z, w) => { 2 | // @affineplane.vec4.create(x, y, z, w) 3 | // 4 | // Parameters: 5 | // x 6 | // a number 7 | // y 8 | // a number 9 | // z 10 | // a number 11 | // w 12 | // a number 13 | // 14 | // Return 15 | // a vec4 16 | // 17 | return { x, y, z, w } 18 | } 19 | -------------------------------------------------------------------------------- /test/helm2/toArray.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | const toArray = helm2.toArray 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transforms to array', (t) => { 6 | t.deepEqual(toArray(helm2.ROT180), [-1, 0, 0, 0]) 7 | t.deepEqual(toArray({ a: 1, b: 2, x: 3, y: 4 }), [1, 2, 3, 4]) 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/quat4/norm.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic norm', (t) => { 6 | t.equal( 7 | quat4.norm({ a: 1, b: 1, c: 1, d: 1 }), 8 | 2, 9 | 'should be square root of squared sum' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/ray3/copy.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: copy ray3', (t) => { 5 | const r = { x: 1, y: 2, z: 3, dx: 1, dy: 2, dz: 3 } 6 | const c = ray3.copy(r) 7 | 8 | t.deepEqual(r, c, 'same content') 9 | t.notEqual(r, c, 'not same object') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/box2/getSize.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box2.getSize(box) 3 | // 4 | // Get the size of the box. 5 | // 6 | // Parameters: 7 | // box 8 | // a box2 in the reference basis. 9 | // 10 | // Return 11 | // a size2 in the reference basis. 12 | // 13 | return { 14 | w: box.w, 15 | h: box.h 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/plane2/compose.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane2.compose(planea, planeb) 2 | // 3 | // Combine two planes together. 4 | // 5 | // Parameters: 6 | // planea 7 | // a plane2 on the reference plane 8 | // planeb 9 | // a plane2 on the planea 10 | // 11 | // Return 12 | // a plane2 on the reference plane 13 | // 14 | module.exports = require('../helm2/compose') 15 | -------------------------------------------------------------------------------- /lib/point2/fromArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (arrp) => { 2 | // @affineplane.point2.fromArray(arrp) 3 | // 4 | // Create { x, y } point from array [x, y]. 5 | // 6 | // Parameters: 7 | // arrp 8 | // a two-element array 9 | // 10 | // Return 11 | // a point2 12 | // 13 | return { 14 | x: arrp[0], 15 | y: arrp[1] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/point3/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = (p) => { 2 | // @affineplane.point3.toArray(p) 3 | // 4 | // Get the point3 object as an array. 5 | // Compatible with affineplane.point3.fromArray. 6 | // 7 | // Parameters: 8 | // p 9 | // a point3 10 | // 11 | // Return 12 | // an array [x, y, z] 13 | // 14 | return [p.x, p.y, p.z] 15 | } 16 | -------------------------------------------------------------------------------- /lib/quat4/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (a, b, c, d) => { 2 | // @affineplane.quat4.create(a, b, c, d) 3 | // 4 | // Parameters: 5 | // a 6 | // a number 7 | // b 8 | // a number 9 | // c 10 | // a number 11 | // d 12 | // a number 13 | // 14 | // Return 15 | // a quat4 16 | // 17 | return { a, b, c, d } 18 | } 19 | -------------------------------------------------------------------------------- /lib/ray3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (r) => { 2 | // @affineplane.ray3.copy(r) 3 | // 4 | // Copy ray object. 5 | // 6 | // Parameters 7 | // r 8 | // a ray3 9 | // 10 | // Return 11 | // a ray3 12 | // 13 | return { 14 | x: r.x, 15 | y: r.y, 16 | z: r.z, 17 | dx: r.dx, 18 | dy: r.dy, 19 | dz: r.dz 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/dist2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (d) => { 2 | // @affineplane.dist2.create(d) 3 | // 4 | // Create a distance measure. 5 | // Basically it is just the absolute value of the number. 6 | // 7 | // Parameters 8 | // d 9 | // a number 10 | // 11 | // Return 12 | // a number, always zero or positive. 13 | // 14 | return Math.abs(d) 15 | } 16 | -------------------------------------------------------------------------------- /lib/helm2/getTranslation.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm2.getTranslation(tr) 3 | // 4 | // Get translation component of the transformation as a vector. 5 | // 6 | // Parameters: 7 | // tr 8 | // a helm2 9 | // 10 | // Return: 11 | // a vec2 12 | // 13 | return { 14 | x: tr.x, 15 | y: tr.y 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/orient2/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, q) => { 2 | // @affineplane.orient2.equal(p, q) 3 | // 4 | // Test if two orientations are strictly equal in value. 5 | // 6 | // Parameters 7 | // p 8 | // an orient2 9 | // q 10 | // an orient2 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | return p.a === q.a && p.b === q.b 16 | } 17 | -------------------------------------------------------------------------------- /lib/vec2/dot.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.dot(v, w) 3 | // 4 | // The dot product of two vectors, 5 | // also called the scalar product. 6 | // 7 | // Parameters: 8 | // v 9 | // a vec2 10 | // w 11 | // a vec2 12 | // 13 | // Return 14 | // a number 15 | // 16 | return v.x * w.x + v.y * w.y 17 | } 18 | -------------------------------------------------------------------------------- /test/angle/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | modulo: require('./modulo.test'), 4 | degToRad: require('./degToRad.test'), 5 | radToDeg: require('./radToDeg.test') 6 | } 7 | 8 | module.exports = (t) => { 9 | Object.keys(units).forEach((unitName) => { 10 | t.test('affineplane.angle.' + unitName, units[unitName]) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/plane2/create.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic create', (t) => { 5 | const span = { x: 1, y: 2 } 6 | const origin = { x: 3, y: 4 } 7 | t.deepEqual( 8 | plane2.create(origin, span), 9 | { a: 1, b: 2, x: 3, y: 4 } 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/point2/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic transit from plane', (t) => { 5 | const plane = { a: 1, b: 0, x: 2, y: 3 } 6 | 7 | t.deepEqual( 8 | point2.transitFrom({ x: 2, y: 3 }, plane), 9 | { x: 4, y: 6 } 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/sphere3/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../lib/sphere3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic transit to plane', (t) => { 5 | t.deepEqual(sphere3.transitTo( 6 | { x: 20, y: 30, z: 40, r: 40 }, 7 | { a: 1, b: 0, x: 20, y: 30, z: 40 } 8 | ), { x: 0, y: 0, z: 0, r: 40 }) 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/point2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x, y) { 2 | // @affineplane.point2.create(x, y) 3 | // 4 | // Create a point2 object: `{ x, y }`. 5 | // 6 | // Parameters 7 | // x 8 | // a number. The x coordinate. 9 | // y 10 | // a number. The y coordinate. 11 | // 12 | // Return 13 | // a point2 14 | // 15 | return { x, y } 16 | } 17 | -------------------------------------------------------------------------------- /lib/scalar2/create.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar2.create(d) 2 | // 3 | // Create a valid scalar. Basically it is just the number itself. 4 | // 5 | // Parameters 6 | // d 7 | // a number 8 | // 9 | // Return 10 | // a number, the scalar. 11 | // 12 | // Throws 13 | // if the argument is not a number or is NaN 14 | // 15 | module.exports = require('../scalar1/create') 16 | -------------------------------------------------------------------------------- /lib/vec3/dot.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec3.dot(v, w) 3 | // 4 | // Dot product of two vectors, 5 | // also called the scalar product. 6 | // 7 | // Parameters: 8 | // v 9 | // a vec3 10 | // w 11 | // a vec3 12 | // 13 | // Return 14 | // a number 15 | // 16 | return v.x * w.x + v.y * w.y + v.z * w.z 17 | } 18 | -------------------------------------------------------------------------------- /lib/vec3/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec3.equal(v, w) 3 | // 4 | // Test if vectors v, w are equal in value. 5 | // 6 | // Parameters 7 | // v 8 | // a vec3 9 | // w 10 | // a vec3 11 | // 12 | // Return 13 | // a boolean, true if equal 14 | // 15 | return v.x === w.x && v.y === w.y && v.z === w.z 16 | } 17 | -------------------------------------------------------------------------------- /test/epsilon/index.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const EPS = affineplane.epsilon 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: epsilon magnitude', (t) => { 6 | t.ok(EPS > Number.MIN_VALUE, 'epsilon larger than MIN_VALUE') 7 | t.ok(EPS * EPS > Number.MIN_VALUE, 'epsilon^2 larger than MIN_VALUE') 8 | 9 | t.end() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test/line2/at.test.js: -------------------------------------------------------------------------------- 1 | const line2 = require('../../lib/line2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic at', (t) => { 5 | const line = { origin: { x: 1, y: 1 }, span: { x: 1, y: 0 } } 6 | t.deepEqual( 7 | line2.at(line, 3), 8 | { x: 4, y: 1 }, 9 | 'three spans away from origin' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/box2/getArea.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box2.getArea(box) 3 | // 4 | // Compute box area. This returns the area in the reference basis. 5 | // 6 | // Parameters 7 | // box 8 | // a box2, in the reference basis. 9 | // 10 | // Return 11 | // a number, the area in the reference basis. 12 | // 13 | return box.w * box.h 14 | } 15 | -------------------------------------------------------------------------------- /lib/helm3/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = (tr) => { 2 | // @affineplane.helm3.copy(tr) 3 | // @affineplane.helm3.clone 4 | // 5 | // Parameters 6 | // tr 7 | // a helm3, a transform 8 | // 9 | // Return 10 | // a helm3, a transform 11 | // 12 | return { 13 | a: tr.a, 14 | b: tr.b, 15 | x: tr.x, 16 | y: tr.y, 17 | z: tr.z 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/path2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (points) => { 2 | // @affineplane.path2.create(points) 3 | // 4 | // Create a path on plane. Deep-clones the points array. 5 | // 6 | // Parameters: 7 | // points 8 | // array of point2 9 | // 10 | // Return: 11 | // a path2, array of points 12 | // 13 | return points.map(p => { return { x: p.x, y: p.y } }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/plane3/getScale.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.getScale(plane) 2 | // 3 | // The length of the basis vector, the scale multiplier. 4 | // 5 | // Parameters 6 | // plane 7 | // a plane3 on the reference plane 8 | // 9 | // Return 10 | // a number, the scale multiplier with respect to 11 | // .. the reference plane. 12 | // 13 | module.exports = require('../plane2/getScale') 14 | -------------------------------------------------------------------------------- /lib/point2/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, q) => { 2 | // @affineplane.point2.equal(p, q) 3 | // @affineplane.point2.equals 4 | // 5 | // Test if points p, q are equal. 6 | // 7 | // Parameters 8 | // p 9 | // a point2 10 | // q 11 | // a point2 12 | // 13 | // Return 14 | // a boolean 15 | // 16 | return p.x === q.x && p.y === q.y 17 | } 18 | -------------------------------------------------------------------------------- /lib/sphere2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, r) => { 2 | // @affineplane.sphere2.create(x, y, r) 3 | // 4 | // Create a sphere2 object. 5 | // 6 | // Parameters: 7 | // x 8 | // a number 9 | // y 10 | // a number 11 | // r 12 | // a number, the radius 13 | // 14 | // Return 15 | // a sphere2 16 | // 17 | return { x, y, r } 18 | } 19 | -------------------------------------------------------------------------------- /lib/vec2/add.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.add(v, w) 3 | // 4 | // Add two vectors. See vector.sum to add many vectors. 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // w 10 | // a vec2 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: v.x + w.x, 17 | y: v.y + w.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec2/max.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.max(v, w) 3 | // 4 | // Element-wise maximum of two vectors. 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // w 10 | // a vec2 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: Math.max(v.x, w.x), 17 | y: Math.max(v.y, w.y) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec2/min.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.min(v, w) 3 | // 4 | // Element-wise minimum of two vectors 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // w 10 | // a vec2 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: Math.min(v.x, w.x), 17 | y: Math.min(v.y, w.y) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/box2/offset.test.js: -------------------------------------------------------------------------------- 1 | const box2 = require('../../lib/box2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic box offset', (t) => { 5 | const b = { a: 1, b: 0, x: 0, y: 0, w: 0, h: 0 } 6 | t.deepEqual( 7 | box2.offset(b, 10, 20), 8 | { a: 1, b: 0, x: 10, y: 20, w: 0, h: 0 }, 9 | 'trivial' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/line2/normal.test.js: -------------------------------------------------------------------------------- 1 | const line2 = require('../../lib/line2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic normal', (t) => { 5 | const line = { origin: { x: 1, y: 1 }, span: { x: 1, y: 1 } } 6 | t.deepEqual( 7 | line2.normal(line), 8 | { x: -1, y: 1 }, 9 | 'should give right normal' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/plane3/create.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic create', (t) => { 5 | const origin = { x: 1, y: 2, z: 3 } 6 | const span = { x: 4, y: 5 } 7 | t.deepEqual( 8 | plane3.create(origin, span), 9 | { a: 4, b: 5, x: 1, y: 2, z: 3 } 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/angle/degToRad.js: -------------------------------------------------------------------------------- 1 | module.exports = (deg) => { 2 | // @affineplane.angle.degToRad(deg) 3 | // 4 | // Convert angle from degrees to radians, for example 720 becomes 4π. 5 | // 6 | // Parameters: 7 | // deg 8 | // a number, an angle in degrees. 9 | // 10 | // Return 11 | // a number, the angle in radians. 12 | // 13 | return Math.PI * deg / 180 14 | } 15 | -------------------------------------------------------------------------------- /lib/angle/radToDeg.js: -------------------------------------------------------------------------------- 1 | module.exports = (rad) => { 2 | // @affineplane.angle.radToDeg(rad) 3 | // 4 | // Convert angle from radians to degrees. For example 4π becomes 720. 5 | // 6 | // Parameters: 7 | // rad 8 | // a number, an angle in radians. 9 | // 10 | // Return 11 | // a number, the angle in degrees. 12 | // 13 | return 180 * rad / Math.PI 14 | } 15 | -------------------------------------------------------------------------------- /lib/box2/getAngle.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box2.getAngle(box) 3 | // 4 | // Compute box angle in radians with respect to the reference basis. 5 | // 6 | // Parameters 7 | // box 8 | // a box2, in the reference basis. 9 | // 10 | // Return 11 | // a number, the angle in radians. 12 | // 13 | return Math.atan2(box.b, box.a) 14 | } 15 | -------------------------------------------------------------------------------- /lib/box3/getSize.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box3.getSize(box) 3 | // 4 | // Get the size of the box. 5 | // 6 | // Parameters: 7 | // box 8 | // a box3 in the reference basis. 9 | // 10 | // Return 11 | // a size3 in the reference basis. 12 | // 13 | return { 14 | w: box.w, 15 | h: box.h, 16 | d: box.d 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/circle3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.equal(c, d) 2 | // 3 | // Test if two spheres are strictly equal in radius and position. 4 | // See affineplane.circle3.almostEqual for loose comparison. 5 | // 6 | // Parameters 7 | // c 8 | // a circle3 9 | // d 10 | // a circle3 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | module.exports = require('../sphere3/equal') 16 | -------------------------------------------------------------------------------- /lib/plane2/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane2.equal(p1, p2) 2 | // 3 | // Test if two planes are strictly equal in their properties. 4 | // See affineplane.plane2.almostEqual for a relaxed alternative. 5 | // 6 | // Parameters: 7 | // p1 8 | // a plane2 9 | // p2 10 | // a plane2 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | module.exports = require('../helm2/equal') 16 | -------------------------------------------------------------------------------- /lib/plane3/equal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.equal(p1, p2) 2 | // 3 | // Test if two planes are strictly equal in their properties. 4 | // See affineplane.plane3.almostEqual for a relaxed alternative. 5 | // 6 | // Parameters: 7 | // p1 8 | // a plane3 9 | // p2 10 | // a plane3 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | module.exports = require('../helm3/equal') 16 | -------------------------------------------------------------------------------- /lib/poly2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (points) => { 2 | // @affineplane.poly2.create(points) 3 | // 4 | // Create a polygon on plane. Deep-clones the points array. 5 | // 6 | // Parameters: 7 | // points 8 | // array of point2 9 | // 10 | // Return: 11 | // a poly2, array of points 12 | // 13 | return points.map(p => { return { x: p.x, y: p.y } }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/scalar3/create.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar3.create(d) 2 | // 3 | // Create a valid third-order scalar. Basically it is just the number itself. 4 | // 5 | // Parameters 6 | // d 7 | // a number 8 | // 9 | // Return 10 | // a number, the scalar. 11 | // 12 | // Throws 13 | // if the argument is not a number or is NaN 14 | // 15 | module.exports = require('../scalar1/create') 16 | -------------------------------------------------------------------------------- /test/box3/getAngle.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const box3 = affineplane.box3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | const bb = { a: 0, b: 1, x: 10, y: 20, z: 30, w: 10, h: 6, d: 3 } 7 | const deg90 = Math.PI / 2 8 | t.almostEqual(box3.getAngle(bb), deg90, 'should 90 deg') 9 | 10 | t.end() 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /test/quat4/fromVector.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic fromVector', (t) => { 6 | t.deepEqual( 7 | quat4.fromVector({ x: 1, y: 2, z: -3 }), 8 | { a: 0, b: 1, c: 2, d: -3 }, 9 | 'scalar should be zero' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/helm3/getTranslation.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm3.getTranslation(tr) 3 | // 4 | // Get translation component of the transformation as a vector. 5 | // 6 | // Parameters: 7 | // tr 8 | // a helm3 9 | // 10 | // Return: 11 | // a vec3 12 | // 13 | return { 14 | x: tr.x, 15 | y: tr.y, 16 | z: tr.z 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/path3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (points) => { 2 | // @affineplane.path3.create(points) 3 | // 4 | // Create a path on plane. Deep-clones the points array. 5 | // 6 | // Parameters: 7 | // points 8 | // array of point3 9 | // 10 | // Return: 11 | // a path3, array of points 12 | // 13 | return points.map(p => { return { x: p.x, y: p.y, z: p.z } }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/vec2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x, y) { 2 | // @affineplane.vec2.create(x, y) 3 | // 4 | // Create a vector object `{ x, y }`. 5 | // 6 | // Parameters 7 | // x 8 | // a number. The translation along x-axis 9 | // y 10 | // a number. The translation along y-axis 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { x, y } 16 | } 17 | -------------------------------------------------------------------------------- /lib/vec2/difference.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.difference(v, w) 3 | // 4 | // A vector between v and w, in other words, v - w. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec2 9 | // w 10 | // a vec2 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: v.x - w.x, 17 | y: v.y - w.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec4/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec4.equal(v, w) 3 | // 4 | // Test if vectors v, w are equal in value. 5 | // 6 | // Parameters 7 | // v 8 | // a vec4 9 | // w 10 | // a vec4 11 | // 12 | // Return 13 | // a boolean, true if equal 14 | // 15 | return v.x === w.x && v.y === w.y && v.z === w.z && v.w === w.w 16 | } 17 | -------------------------------------------------------------------------------- /test/dir2/projectToPlane.test.js: -------------------------------------------------------------------------------- 1 | const dir2 = require('../../lib/dir2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: smoke', (t) => { 5 | const plane = { a: 0, b: 1, x: 0, y: 0, z: 0 } 6 | t.deepEqual( 7 | dir2.projectTo({ x: 1, y: 0 }, plane), 8 | { x: 0, y: -1 }, 9 | 'identity plane; should lose z' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/ray3/create.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create ray3', (t) => { 5 | const origin = { x: 1, y: 2, z: 3 } 6 | const span = { x: 1, y: 2, z: 3 } 7 | const r = ray3.create(origin, span) 8 | 9 | t.deepEqual(r, { x: 1, y: 2, z: 3, dx: 1, dy: 2, dz: 3 }, 'same values') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/segment2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const segment2 = affineplane.segment2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | segment2.create({ x: 0, y: 0 }, { x: 1, y: 1 }), 8 | [{ x: 0, y: 0 }, { x: 1, y: 1 }], 9 | 'should form array' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/helm2/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm2.toArray(tr) 3 | // 4 | // Return an array representation of the transformation. 5 | // Compatible with affineplane.helm2.fromArray. 6 | // 7 | // Parameters: 8 | // tr 9 | // a helm2 10 | // 11 | // Return 12 | // an array, [a, b, x, y] 13 | // 14 | return [tr.a, tr.b, tr.x, tr.y] 15 | } 16 | -------------------------------------------------------------------------------- /lib/helm3/getRotation.js: -------------------------------------------------------------------------------- 1 | // @affineplane.helm3.getRotation(tr) 2 | // 3 | // Get the rotation component of the transform in radians. 4 | // This is rotation around z-axis to right hand direction. 5 | // 6 | // Parameters: 7 | // tr 8 | // a helm3 9 | // 10 | // Return: 11 | // a number, angle in radians 12 | // 13 | module.exports = function (tr) { 14 | return Math.atan2(tr.b, tr.a) 15 | } 16 | -------------------------------------------------------------------------------- /lib/sphere2/atCenter.js: -------------------------------------------------------------------------------- 1 | module.exports = (sp) => { 2 | // @affineplane.sphere2.atCenter(sp) 3 | // 4 | // Get the center point of the sphere. 5 | // Note that the sphere2 object itself can act as a point2 in many cases. 6 | // 7 | // Parameters: 8 | // a sphere2 9 | // 10 | // Return 11 | // a point2 12 | // 13 | return { 14 | x: sp.x, 15 | y: sp.y 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/box2/translate.test.js: -------------------------------------------------------------------------------- 1 | const box2 = require('../../lib/box2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic box translate', (t) => { 5 | const b = { a: 1, b: 0, x: 0, y: 0, w: 0, h: 0 } 6 | t.deepEqual( 7 | box2.translate(b, { x: 10, y: 20 }), 8 | { a: 1, b: 0, x: 10, y: 20, w: 0, h: 0 }, 9 | 'trivial' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/helm2/toMatrix.test.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../index').helm2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: correct properties', (t) => { 5 | const tr = { a: 1, b: 2, x: 3, y: 4 } 6 | 7 | t.deepEqual(helm2.toMatrix(tr), { 8 | a: 1, 9 | b: 2, 10 | c: -2, 11 | d: 1, 12 | e: 3, 13 | f: 4 14 | }) 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /test/point3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: margin', (t) => { 5 | const p = { x: 0, y: 0, z: 0 } 6 | const q = { x: 3, y: 3, z: 3 } 7 | t.false(point3.almostEqual(p, q, 1)) 8 | t.false(point3.almostEqual(p, q, 8)) 9 | t.true(point3.almostEqual(p, q, 9)) 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/quat4/conjugate.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic conjugate', (t) => { 6 | t.deepEqual( 7 | quat4.conjugate({ a: 1, b: 2, c: -3, d: 4 }), 8 | { a: 1, b: -2, c: 3, d: -4 }, 9 | 'vector part should be negated' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/circle3/translate.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.translate(c, vec) 2 | // 3 | // Translate a circle by the vector. Does not affect radius. 4 | // See affineplane.circle3.offset to translate by scalars. 5 | // 6 | // Parameters: 7 | // c 8 | // a circle3 9 | // vec 10 | // a vec3 11 | // 12 | // Return 13 | // a circle3, translated 14 | // 15 | module.exports = require('../sphere3/translate') 16 | -------------------------------------------------------------------------------- /lib/dir2/fromPolar.js: -------------------------------------------------------------------------------- 1 | module.exports = (r) => { 2 | // @affineplane.dir2.fromPolar(r) 3 | // @affineplane.dir2.create 4 | // 5 | // Create a new direction from an angle. 6 | // 7 | // Parameters 8 | // r 9 | // a number. The angle in radians. 10 | // 11 | // Return 12 | // a dir2 13 | // 14 | 15 | return { 16 | x: Math.cos(r), 17 | y: Math.sin(r) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/quat4/fromVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (vec) => { 2 | // @affineplane.quat4.fromVector(vec) 3 | // 4 | // Construct a vector quaternion i.e. a quaternion with zero scalar part. 5 | // 6 | // Parameters: 7 | // vec 8 | // a vec3 9 | // 10 | // Return 11 | // a quat4 12 | // 13 | return { 14 | a: 0, 15 | b: vec.x, 16 | c: vec.y, 17 | d: vec.z 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/size2/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (width, height) => { 2 | // @affineplane.size2.create(width, height) 3 | // 4 | // Create a size2 object. 5 | // 6 | // Parameters: 7 | // width 8 | // a number 9 | // height 10 | // a number 11 | // 12 | // Return 13 | // a size2 14 | // 15 | return { 16 | w: Math.abs(width), 17 | h: Math.abs(height) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/box2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const box2 = affineplane.box2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | box2.create({ a: 1, b: 0, x: 3, y: 4 }, { w: 1, h: -2 }), 8 | { a: 1, b: 0, x: 3, y: 4, w: 1, h: 2 }, 9 | 'should be a box object' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/path2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path2 = affineplane.path2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | path2.create([{ x: 0, y: 0, z: 0 }, { x: 1, y: 1 }]), 8 | [{ x: 0, y: 0 }, { x: 1, y: 1 }], 9 | 'should remove extra property' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/segment3/conversions.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const segment3 = affineplane.segment3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: toVector', (t) => { 6 | t.deepEqual( 7 | segment3.toVector([{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }]), 8 | { x: 1, y: 1, z: 1 }, 9 | 'should create a vector' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/vec4/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | add: require('./add.test'), 4 | almostEqual: require('./almostEqual.test'), 5 | equal: require('./equal.test'), 6 | validate: require('./validate.test') 7 | } 8 | 9 | module.exports = (t) => { 10 | Object.keys(units).forEach((unitName) => { 11 | t.test('affineplane.vec4.' + unitName, units[unitName]) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/helm2/getDilation.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm2.getDilation(tr) 3 | // @affineplane.helm2.getScale 4 | // 5 | // Get the dilation component of the transformation. 6 | // 7 | // Parameters: 8 | // tr 9 | // a helm2 10 | // 11 | // Return: 12 | // a number, the scale multiplier. 13 | // 14 | return Math.sqrt(tr.b * tr.b + tr.a * tr.a) 15 | } 16 | -------------------------------------------------------------------------------- /lib/ray3/getOrigin.js: -------------------------------------------------------------------------------- 1 | module.exports = (r) => { 2 | // @affineplane.ray3.getOrigin(r) 3 | // 4 | // Get the origin point of the ray. Note that you can also use the ray 5 | // object itself as a point. 6 | // 7 | // Parameters 8 | // r 9 | // a ray3 10 | // 11 | // Return 12 | // a point3 13 | // 14 | return { 15 | x: r.x, 16 | y: r.y, 17 | z: r.z 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec2/invert.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec2.invert(v) 3 | // @affineplane.vec2.negate 4 | // 5 | // Negate the vector. For example `inverse({ x: 1, y: -1 })` returns 6 | // `{ x: -1, y: 1 }`. 7 | // 8 | // Parameters 9 | // v 10 | // a vec2 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: -v.x, 17 | y: -v.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/dist2/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dist2 = affineplane.dist2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic distance equality', (t) => { 6 | t.ok( 7 | dist2.equal(1, 1), 8 | 'numbers equal' 9 | ) 10 | 11 | t.notOk( 12 | dist2.equal(0, 1), 13 | 'numbers not equal' 14 | ) 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /test/plane2/fromFeatures.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic fromFeatures', (t) => { 5 | t.almostEqual( 6 | plane2.fromFeatures({ 7 | angle: Math.PI / 2, 8 | scale: 2, 9 | origin: { x: 3, y: 4 } 10 | }), 11 | { a: 0, b: 2, x: 3, y: 4 } 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/plane2/validate.test.js: -------------------------------------------------------------------------------- 1 | // Light-weight tests because 2 | // plane2.validate is helm2.validate 3 | // which has wider test suite. 4 | // 5 | const plane2 = require('../../lib/plane2') 6 | 7 | module.exports = (ts) => { 8 | ts.test('case: smoke', (t) => { 9 | t.true(plane2.validate({ a: 1, b: 2, x: 3, y: 4 })) 10 | t.false(plane2.validate({ a: 1, b: 2, x: 3 })) 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/scalar2/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar2 = affineplane.scalar2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.ok( 7 | scalar2.almostEqual(2, 2), 8 | 'zero diff' 9 | ) 10 | t.notOk( 11 | scalar2.almostEqual(-1, 1), 12 | 'different numbers' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/scalar3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar3 = affineplane.scalar3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke', (t) => { 6 | t.ok( 7 | scalar3.almostEqual(2, 2), 8 | 'zero diff' 9 | ) 10 | t.notOk( 11 | scalar3.almostEqual(-1, 1), 12 | 'different numbers' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/helm2/fromVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (vec) => { 2 | // @affineplane.helm2.fromVector(vec) 3 | // 4 | // Create a helm2 transformation from a translation vector. 5 | // 6 | // Parameters: 7 | // vec 8 | // a vec2, the displacement vector 9 | // 10 | // Return: 11 | // a helm2 12 | // 13 | return { 14 | a: 1, 15 | b: 0, 16 | x: vec.x, 17 | y: vec.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/helm3/toArray.js: -------------------------------------------------------------------------------- 1 | module.exports = function (tr) { 2 | // @affineplane.helm3.toArray(tr) 3 | // 4 | // Serializes the transformation into an array representation. 5 | // Compatible with affineplane.helm3.fromArray. 6 | // 7 | // Parameters: 8 | // tr 9 | // a helm3 10 | // 11 | // Return 12 | // an array [a, b, x, y, z] 13 | // 14 | return [tr.a, tr.b, tr.x, tr.y, tr.z] 15 | } 16 | -------------------------------------------------------------------------------- /lib/rect2/fitScale.js: -------------------------------------------------------------------------------- 1 | module.exports = (rect, target) => { 2 | // TODO 3 | // alias scaleToFit, scaleToMatch, fitScaleInside 4 | // scaleToFitInside, scaleToFitOutside, fitInsideByDilation 5 | // fitOutsideByScale, scaleToMatch 6 | // 7 | // Parameters: 8 | // rect 9 | // a rect2 10 | // target 11 | // a path2 or rect2 12 | // 13 | // Return 14 | // a rect2 15 | // 16 | } 17 | -------------------------------------------------------------------------------- /test/box3/offset.test.js: -------------------------------------------------------------------------------- 1 | const box3 = require('../../lib/box3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic translateBy', (t) => { 5 | const b = { a: 1, b: 0, x: 1, y: 2, z: 3, w: 0, h: 0, d: 0 } 6 | t.deepEqual( 7 | box3.translateBy(b, 10, 20, 30), 8 | { a: 1, b: 0, x: 11, y: 22, z: 33, w: 0, h: 0, d: 0 }, 9 | 'trivial' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/line2/fromPoints.test.js: -------------------------------------------------------------------------------- 1 | const line2 = require('../../lib/line2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create line2 from two points', (t) => { 5 | const p1 = { x: 2, y: 1 } 6 | const p2 = { x: 5, y: 4 } 7 | t.deepEqual( 8 | line2.fromPoints(p1, p2), 9 | { origin: p1, span: { x: 3, y: 3 } }, 10 | 'correct span' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/scalar1/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar1 = affineplane.scalar1 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic scalar equality', (t) => { 6 | t.ok( 7 | scalar1.equal(1, 1), 8 | 'numbers equal' 9 | ) 10 | 11 | t.notOk( 12 | scalar1.equal(0, 1), 13 | 'numbers not equal' 14 | ) 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /test/sphere2/fromPoints.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create sphere2 from two points', (t) => { 5 | const p1 = { x: 1, y: 1 } 6 | const p2 = { x: 5, y: 4 } 7 | t.deepEqual( 8 | sphere2.fromPoints(p1, p2), 9 | { x: 1, y: 1, r: 5 }, 10 | 'correct origin and radius' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /lib/plane3/orientation.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.orientation(plane) 2 | // 3 | // The orientation of the plane, i.e. the rotation from default. 4 | // If the plane is singular, falls back to the default orientation. 5 | // 6 | // Parameters 7 | // plane 8 | // a plane3, in the reference basis 9 | // 10 | // Return 11 | // a orient2, in the reference basis 12 | // 13 | module.exports = require('../plane2/orientation') 14 | -------------------------------------------------------------------------------- /lib/vec4/add.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec4.add(v, w) 3 | // 4 | // Add two vectors together via component-wise addition. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec4 9 | // w 10 | // a vec4 11 | // 12 | // Return 13 | // a vec4 14 | // 15 | return { 16 | x: v.x + w.x, 17 | y: v.y + w.y, 18 | z: v.z + w.z, 19 | w: v.w + w.w 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/vec4/scaleBy.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, m) => { 2 | // @affineplane.vec4.scaleBy(v, m) 3 | // 4 | // Scalar multiplication of a vector. 5 | // 6 | // Parameters: 7 | // v 8 | // a vec4 9 | // m 10 | // a number, a multiplier 11 | // 12 | // Return: 13 | // a vec4 14 | // 15 | return { 16 | x: v.x * m, 17 | y: v.y * m, 18 | z: v.z * m, 19 | w: v.w * m 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/plane3/validate.test.js: -------------------------------------------------------------------------------- 1 | // Light-weight test suite because 2 | // plane3.validate is helm3.validate 3 | // which has wider test suite. 4 | // 5 | const plane3 = require('../../lib/plane3') 6 | 7 | module.exports = (ts) => { 8 | ts.test('case: smoke', (t) => { 9 | t.true(plane3.validate({ a: 1, b: 2, x: 3, y: 4, z: 5 })) 10 | t.false(plane3.validate({ a: 1, b: 2, x: 3, y: 4 })) 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/segment3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const segment3 = affineplane.segment3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | segment3.create({ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }), 8 | [{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }], 9 | 'should form an array' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/utils/transformEqual.js: -------------------------------------------------------------------------------- 1 | const helm2 = require('../../lib/helm2') 2 | const helm2AlmostEqual = helm2.almostEqual 3 | 4 | module.exports = function (actual, expected, message) { 5 | // Custom tape.js assertion. 6 | this._assert(helm2AlmostEqual(actual, expected), { 7 | message: message || 'helm2 should have correct elements', 8 | operator: 'transformEqual', 9 | actual, 10 | expected 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/box3/getVolume.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box3.getVolume(box) 3 | // 4 | // Compute box volume. This returns the volume as a measure 5 | // in the reference basis. 6 | // 7 | // Parameters 8 | // box 9 | // a box3, a cuboid in the reference basis. 10 | // 11 | // Return 12 | // a number, the volume in the reference basis. 13 | // 14 | return box.w * box.h * box.d 15 | } 16 | -------------------------------------------------------------------------------- /lib/plane2/getScale.js: -------------------------------------------------------------------------------- 1 | module.exports = (plane) => { 2 | // @affineplane.plane2.getScale(plane) 3 | // 4 | // The length of the vector. 5 | // 6 | // Parameters 7 | // plane 8 | // a plane2 on the reference plane 9 | // 10 | // Return 11 | // a number, the scale multiplier with respect to 12 | // .. the reference plane. 13 | // 14 | return Math.sqrt(plane.a * plane.a + plane.b * plane.b) 15 | } 16 | -------------------------------------------------------------------------------- /lib/sphere2/size.js: -------------------------------------------------------------------------------- 1 | module.exports = (sphere) => { 2 | // @affineplane.sphere2.size(sphere) 3 | // 4 | // Get the rectangular size of the circle. 5 | // 6 | // Parameters: 7 | // sphere 8 | // a sphere2 in the reference basis. 9 | // 10 | // Return 11 | // a size2 in the reference basis. 12 | // 13 | const diam = sphere.r + sphere.r 14 | return { 15 | w: diam, 16 | h: diam 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/sphere3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, z, r) => { 2 | // @affineplane.sphere3.create(x, y, z, r) 3 | // 4 | // Create a sphere3 object. 5 | // 6 | // Parameters: 7 | // x 8 | // a number 9 | // y 10 | // a number 11 | // z 12 | // a number 13 | // r 14 | // a number, the radius 15 | // 16 | // Return 17 | // a sphere3 18 | // 19 | return { x, y, z, r } 20 | } 21 | -------------------------------------------------------------------------------- /test/box3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const box3 = affineplane.box3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | box3.create({ a: 1, b: 0, x: 3, y: 4, z: 5 }, { w: 1, h: -2, d: 3 }), 8 | { a: 1, b: 0, x: 3, y: 4, z: 5, w: 1, h: 2, d: 3 }, 9 | 'should be a box object' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/box3/translate.test.js: -------------------------------------------------------------------------------- 1 | const box3 = require('../../lib/box3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic box translate', (t) => { 5 | const b = { a: 1, b: 0, x: 0, y: 0, z: 0, w: 0, h: 0, d: 0 } 6 | t.deepEqual( 7 | box3.translate(b, { x: 10, y: 20, z: 30 }), 8 | { a: 1, b: 0, x: 10, y: 20, z: 30, w: 0, h: 0, d: 0 }, 9 | 'trivial' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/line3/at.test.js: -------------------------------------------------------------------------------- 1 | const line3 = require('../../lib/line3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic at', (t) => { 5 | const line = { 6 | origin: { x: 1, y: 1, z: 1 }, 7 | span: { x: 1, y: 0, z: 0 } 8 | } 9 | 10 | t.deepEqual( 11 | line3.at(line, 3), 12 | { x: 4, y: 1, z: 1 }, 13 | 'three spans away from origin' 14 | ) 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /test/path3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path3 = affineplane.path3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.deepEqual( 7 | path3.create([{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1, w: 2 }]), 8 | [{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }], 9 | 'should remove extra property' 10 | ) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/point3/toArray.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: happy arrays', (t) => { 5 | t.deepEqual( 6 | point3.toArray({ x: 1, y: 2, z: 3 }), 7 | [1, 2, 3] 8 | ) 9 | t.deepEqual( 10 | point3.toArray({ x: 1, y: 2, z: 3, r: 4 }), 11 | [1, 2, 3], 12 | 'strip extra elements' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/quat4/add.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic add', (t) => { 6 | t.deepEqual( 7 | quat4.add( 8 | { a: 1, b: 2, c: 3, d: 4 }, 9 | { a: 1, b: 2, c: 3, d: 4 } 10 | ), 11 | { a: 2, b: 4, c: 6, d: 8 }, 12 | 'should be double' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/segment3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | conversions: require('./conversions.test'), 4 | create: require('./create.test'), 5 | transitions: require('./transitions.test'), 6 | validate: require('./validate.test') 7 | } 8 | 9 | module.exports = (t) => { 10 | Object.keys(units).forEach((unitName) => { 11 | t.test('affineplane.segment3.' + unitName, units[unitName]) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/dir2/toPolar.js: -------------------------------------------------------------------------------- 1 | module.exports = (dir) => { 2 | // @affineplane.dir2.toPolar(dir) 3 | // @affineplane.dir2.toAngle 4 | // 5 | // Get the direction as angle around z-axis measured from positive x-axis. 6 | // 7 | // Parameters: 8 | // dir 9 | // a dir2 object or unit vec2. 10 | // 11 | // Return 12 | // a number, an angle in radians in ]-π, π]. 13 | // 14 | return Math.atan2(dir.y, dir.x) 15 | } 16 | -------------------------------------------------------------------------------- /lib/point3/round.js: -------------------------------------------------------------------------------- 1 | const round = Math.round 2 | 3 | module.exports = (p) => { 4 | // @affineplane.point3.round(p) 5 | // 6 | // Move point to the closest integer coordinate. 7 | // 8 | // Parameters: 9 | // p 10 | // a point3 11 | // 12 | // Return 13 | // a point3, having integer coordinates. 14 | // 15 | return { 16 | x: round(p.x), 17 | y: round(p.y), 18 | z: round(p.z) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/quat4/add.js: -------------------------------------------------------------------------------- 1 | module.exports = (q, p) => { 2 | // @affineplane.quat4.add(q, p) 3 | // 4 | // Add two quaternions together via component-wise addition. 5 | // 6 | // Parameters: 7 | // q 8 | // a quat4 9 | // p 10 | // a quat4 11 | // 12 | // Return 13 | // a quat4 14 | // 15 | return { 16 | a: q.a + p.a, 17 | b: q.b + p.b, 18 | c: q.c + p.c, 19 | d: q.d + p.d 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/segment3/toVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (seg) => { 2 | // @affineplane.segment3.toVector(seg) 3 | // 4 | // Convert segment to a vector from the first to the second segment point. 5 | // 6 | // Parameter 7 | // seg 8 | // a segment3 9 | // 10 | // Return 11 | // a vec3 12 | // 13 | return { 14 | x: seg[1].x - seg[0].x, 15 | y: seg[1].y - seg[0].y, 16 | z: seg[1].z - seg[0].z 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/line3/fromPoints.test.js: -------------------------------------------------------------------------------- 1 | const line3 = require('../../lib/line3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create line3 from two points', (t) => { 5 | const p1 = { x: 2, y: 1, z: 0 } 6 | const p2 = { x: 5, y: 4, z: 3 } 7 | t.deepEqual( 8 | line3.fromPoints(p1, p2), 9 | { origin: p1, span: { x: 3, y: 3, z: 3 } }, 10 | 'correct span' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/plane2/compose.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic compose', (t) => { 5 | const planea = { a: 1, b: 0, x: 1, y: 1 } 6 | const planeb = { a: 2, b: 0, x: 2, y: 2 } 7 | 8 | t.deepEqual( 9 | plane2.compose(planea, planeb), 10 | { a: 2, b: 0, x: 3, y: 3 }, 11 | 'plane on plane' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/point3/fromArray.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic array', (t) => { 5 | t.deepEqual( 6 | point3.fromArray([1, 2, 3]), 7 | { x: 1, y: 2, z: 3 } 8 | ) 9 | t.deepEqual( 10 | point3.fromArray([1, 2, 3, 4]), 11 | { x: 1, y: 2, z: 3 }, 12 | 'strip extra elements' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/size3/volume.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size3 = affineplane.size3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic volume', (t) => { 6 | const sz = size3.create(1, 2, 3) 7 | t.equal(size3.volume(sz), 6, 'should be absolute value') 8 | 9 | const sz0 = size3.create(1, 0, 3) 10 | t.equal(size3.volume(sz0), 0, 'should allow zero') 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/rect3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (basis, size) => { 2 | // @affineplane.rect3.create(basis, size) 3 | // 4 | // Construct a rect3 object from basis and size. 5 | // 6 | // Parameters: 7 | // basis 8 | // a basis3 9 | // size 10 | // a size2 11 | // 12 | // Return: 13 | // a rect3 14 | // 15 | console.warn('affineplane.rect3 is deprecated. Use box3 instead.') 16 | return { basis, size } 17 | } 18 | -------------------------------------------------------------------------------- /test/helm3/toArray.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../index').helm3 2 | const toArray = helm3.toArray 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transforms to array', (t) => { 6 | t.deepEqual( 7 | toArray(helm3.ROT180), 8 | [-1, 0, 0, 0, 0] 9 | ) 10 | t.deepEqual( 11 | toArray({ a: 1, b: 2, x: 3, y: 4, z: 5 }), 12 | [1, 2, 3, 4, 5] 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/sphere3/fromPoints.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../lib/sphere3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create sphere3 from two points', (t) => { 5 | const p1 = { x: 1, y: 1, z: 1 } 6 | const p2 = { x: 3, y: 3, z: 2 } 7 | t.deepEqual( 8 | sphere3.fromPoints(p1, p2), 9 | { x: 1, y: 1, z: 1, r: 3 }, 10 | 'correct origin and radius' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /lib/circle3/size.js: -------------------------------------------------------------------------------- 1 | module.exports = (c) => { 2 | // @affineplane.circle3.size(c) 3 | // 4 | // Get the cuboid size of a circle. Circles always have zero depth. 5 | // 6 | // Parameters: 7 | // c 8 | // a circle3 in the reference basis. 9 | // 10 | // Return 11 | // a size3 in the reference basis. 12 | // 13 | const diam = c.r + c.r 14 | return { 15 | w: diam, 16 | h: diam, 17 | d: 0 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/size2/atNorm.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz, nw, nh) => { 2 | // @affineplane.size2.atNorm(sz, nw, nh) 3 | // 4 | // Find a point on the area. 5 | // 6 | // Parameters 7 | // sz 8 | // a size2 9 | // nw 10 | // a normalized width in 0..1 11 | // nh 12 | // a normalized height 13 | // 14 | // Return 15 | // a point2 16 | // 17 | return { 18 | x: sz.w * nw, 19 | y: sz.h * nh 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/sphere3/size.js: -------------------------------------------------------------------------------- 1 | module.exports = (sphere) => { 2 | // @affineplane.sphere3.size(sphere) 3 | // 4 | // Get the cuboid size of the sphere. 5 | // 6 | // Parameters: 7 | // sphere 8 | // a sphere3 in the reference basis. 9 | // 10 | // Return 11 | // a size3 in the reference basis. 12 | // 13 | const diam = sphere.r + sphere.r 14 | return { 15 | w: diam, 16 | h: diam, 17 | d: diam 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/angle/modulo.test.js: -------------------------------------------------------------------------------- 1 | const angle = require('../../index').angle 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: limits', (t) => { 6 | t.equal(angle.modulo(1), 1, 'value between limits') 7 | t.equal(angle.modulo(-PI), PI, 'exclude -pi') 8 | t.equal(angle.modulo(PI * 3), PI, 'value over limit') 9 | t.equal(angle.modulo(-3 * PI), PI, 'value below limit') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/line3/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.line3 2 | // 3 | // Directed line object in 3D, 4 | // Represented as an origin point and a spanning vector. 5 | // 6 | // A line3 is an object `{ origin: {x,y,z}, span: {x,y,z} }` 7 | // 8 | 9 | exports.at = require('./at') 10 | exports.create = require('./create') 11 | exports.fromPoints = require('./fromPoints') 12 | exports.intersection = require('./intersection') 13 | exports.validate = require('./validate') 14 | -------------------------------------------------------------------------------- /lib/quat4/difference.js: -------------------------------------------------------------------------------- 1 | module.exports = (q, p) => { 2 | // @affineplane.quat4.difference(q, p) 3 | // @affineplane.quat4.diff 4 | // 5 | // Get the quaternion q - p. 6 | // 7 | // Parameters: 8 | // q 9 | // a quat4 10 | // p 11 | // a quat4 12 | // 13 | // Return 14 | // a quat4 15 | // 16 | return { 17 | a: p.a - q.a, 18 | b: p.b - q.b, 19 | c: p.c - q.c, 20 | d: p.d - q.d 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/rot2/create.js: -------------------------------------------------------------------------------- 1 | const validate = require('./validate') 2 | 3 | module.exports = (a, b) => { 4 | // @affineplane.rot2.create(a, b) 5 | // 6 | // Parameters: 7 | // a 8 | // a number 9 | // b 10 | // a number 11 | // 12 | // Return 13 | // a rot2 14 | // 15 | const rot = { a, b } 16 | 17 | if (!validate(rot)) { 18 | throw new Error('invalid rotation parameters') 19 | } 20 | 21 | return rot 22 | } 23 | -------------------------------------------------------------------------------- /lib/size2/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = function (s, ss) { 2 | // @affineplane.size2.equal(s, ss) 3 | // 4 | // Test if two sizes are strictly equal in value. 5 | // The size objects are allowed to have additional non-equal properties. 6 | // 7 | // Parameters: 8 | // s 9 | // a size2 10 | // ss 11 | // a size2 12 | // 13 | // Return: 14 | // a boolean 15 | // 16 | return s.w === ss.w && s.h === ss.h 17 | } 18 | -------------------------------------------------------------------------------- /test/path2/combine.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path2 = affineplane.path2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic combine', (t) => { 6 | const p0 = [{ x: 0, y: 0 }, { x: 1, y: 1 }] 7 | const p1 = [{ x: 2, y: 2 }] 8 | 9 | t.deepEqual( 10 | path2.combine(p0, p1), 11 | p0.concat(p1), 12 | 'should copy arrays together' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/quat4/difference.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic diff', (t) => { 6 | t.deepEqual( 7 | quat4.diff( 8 | { a: 1, b: 2, c: 3, d: 4 }, 9 | { a: 1, b: 2, c: 3, d: 4 } 10 | ), 11 | { a: 0, b: 0, c: 0, d: 0 }, 12 | 'should be zero quaternion' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/rect2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const rect2 = affineplane.rect2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | const basis = { a: 1, b: 0, x: 0, y: 0 } 7 | const size = { w: 10, h: 6 } 8 | t.deepEqual( 9 | rect2.create(basis, size), 10 | { basis, size }, 11 | 'should have correct structure' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/sphere2/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: margin', (t) => { 5 | const p = { x: 0, y: 0, r: 0 } 6 | const q = { x: 3, y: 3, r: 3 } 7 | t.false(sphere2.almostEqual(p, q, 1)) 8 | t.false(sphere2.almostEqual(p, q, 8)) 9 | t.true(sphere2.almostEqual(p, q, 9)) 10 | t.true(sphere2.almostEqual(p, q, 10)) 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/dir2/toVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (dir, magn) => { 2 | // @affineplane.dir2.toVector(dir, magn) 3 | // 4 | // Get a vector from the direction with the given length. 5 | // 6 | // Parameters: 7 | // dir 8 | // a dir2 9 | // magn 10 | // a number, the magnitude of the vector to create. 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: dir.x * magn, 17 | y: dir.y * magn 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/plane2/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane2.almostEqual(pa, pb[, tolerance]) 2 | // 3 | // Test if two planes are almost equal. 4 | // 5 | // Parameters: 6 | // pa 7 | // a plane2 8 | // pb 9 | // a plane2 10 | // tolerance 11 | // optional number, default to affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return: 15 | // a boolean 16 | // 17 | module.exports = require('../helm2/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/plane3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.almostEqual(pa, pb[, tolerance]) 2 | // 3 | // Test if two planes are almost equal. 4 | // 5 | // Parameters: 6 | // pa 7 | // a plane3 8 | // pb 9 | // a plane3 10 | // tolerance 11 | // optional number, default to affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return: 15 | // a boolean 16 | // 17 | module.exports = require('../helm3/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/point2/transform.js: -------------------------------------------------------------------------------- 1 | module.exports = function (p, tr) { 2 | // @affineplane.point2.transform(p, tr) 3 | // 4 | // Transform a point. 5 | // 6 | // Parameters 7 | // p 8 | // a point2 9 | // tr 10 | // a helm2, a transform 11 | // 12 | // Return 13 | // a point2, the transformed point 14 | // 15 | return { 16 | x: tr.a * p.x - tr.b * p.y + tr.x, 17 | y: tr.b * p.x + tr.a * p.y + tr.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/ray3/invert.js: -------------------------------------------------------------------------------- 1 | module.exports = (r) => { 2 | // @affineplane.ray3.invert(r) 3 | // @affineplane.ray3.negate 4 | // 5 | // Get a ray with the same magnitude but to opposite direction. 6 | // 7 | // Parameters: 8 | // r 9 | // a ray3 10 | // 11 | // Return 12 | // a ray3 13 | // 14 | return { 15 | x: r.x, 16 | y: r.y, 17 | z: r.z, 18 | dx: -r.dx, 19 | dy: -r.dy, 20 | dz: -r.dz 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/plane3/compose.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic compose', (t) => { 5 | const planea = { a: 1, b: 0, x: 1, y: 2, z: 3 } 6 | const planeb = { a: 2, b: 0, x: 2, y: 3, z: 4 } 7 | 8 | t.deepEqual( 9 | plane3.compose(planea, planeb), 10 | { a: 2, b: 0, x: 3, y: 5, z: 7 }, 11 | 'plane on plane' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/rect3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const rect3 = affineplane.rect3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | const basis = { a: 1, b: 0, x: 0, y: 0, z: 0 } 7 | const size = { w: 10, h: 6 } 8 | t.deepEqual( 9 | rect3.create(basis, size), 10 | { basis, size }, 11 | 'should have correct structure' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /lib/helm3/fromArray.js: -------------------------------------------------------------------------------- 1 | module.exports = function (arr) { 2 | // @affineplane.helm3.fromArray(arr) 3 | // 4 | // Create an affine similarity transform from 5-element array. 5 | // 6 | // Parameter 7 | // arr 8 | // an array of five numbers [a, b, x, y, z] 9 | // 10 | // Return 11 | // a helm3 12 | // 13 | return { 14 | a: arr[0], 15 | b: arr[1], 16 | x: arr[2], 17 | y: arr[3], 18 | z: arr[4] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/orient2/create.js: -------------------------------------------------------------------------------- 1 | const validate = require('./validate') 2 | 3 | module.exports = (a, b) => { 4 | // @affineplane.orient2.create(a, b) 5 | // 6 | // Parameters: 7 | // a 8 | // a number 9 | // b 10 | // a number 11 | // 12 | // Return 13 | // a orient2 14 | // 15 | const ori = { a, b } 16 | 17 | if (!validate(ori)) { 18 | throw new Error('invalid rotation parameters') 19 | } 20 | 21 | return ori 22 | } 23 | -------------------------------------------------------------------------------- /lib/point2/distance.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, q) => { 2 | // @affineplane.point2.distance(p, q) 3 | // 4 | // Distance between two points. 5 | // 6 | // Parameters 7 | // p 8 | // a point2 9 | // q 10 | // a point2 11 | // 12 | // Return 13 | // a number, a distance from p to q (= distance from q to p) 14 | // 15 | const dx = p.x - q.x 16 | const dy = p.y - q.y 17 | 18 | return Math.sqrt(dx * dx + dy * dy) 19 | } 20 | -------------------------------------------------------------------------------- /lib/sphere2/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (s, p) => { 2 | // @affineplane.sphere2.equal(s, p) 3 | // 4 | // Test if two spheres are strictly equal in radius and position. 5 | // See affineplane.sphere2.almostEqual for loose comparison. 6 | // 7 | // Parameters 8 | // s 9 | // a sphere2 10 | // p 11 | // a sphere2 12 | // 13 | // Return 14 | // a boolean 15 | // 16 | return s.x === p.x && s.y === p.y && s.r === p.r 17 | } 18 | -------------------------------------------------------------------------------- /test/line3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | at: require('./at.test'), 4 | create: require('./create.test'), 5 | fromPoints: require('./fromPoints.test'), 6 | intersection: require('./intersection.test'), 7 | validate: require('./validate.test') 8 | } 9 | 10 | module.exports = (t) => { 11 | Object.keys(units).forEach((unitName) => { 12 | t.test('affineplane.line3.' + unitName, units[unitName]) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/vec2/magnitude.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic magnitude', (t) => { 6 | t.equal( 7 | vec2.magnitude({ x: 0, y: 0 }), 8 | 0, 9 | 'zero vector' 10 | ) 11 | 12 | t.almostEqual( 13 | vec2.magnitude({ x: 3, y: 4 }), 14 | 5, 15 | 'simple magnitude' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /lib/plane3/getNormal.js: -------------------------------------------------------------------------------- 1 | // @affineplane.plane3.getNormal(plane) 2 | // 3 | // Get a unit vector perpendicular to the plane. 4 | // 5 | // Parameters: 6 | // plane 7 | // a plane3 on the reference plane 8 | // 9 | // Return: 10 | // a vec3, the plane normal vector. 11 | // 12 | module.exports = function (plane) { 13 | // Because all planes are on xy, there is one 14 | // normal vector shared by all the planes. 15 | return { x: 0, y: 0, z: 1 } 16 | } 17 | -------------------------------------------------------------------------------- /lib/point2/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.point2.almostEqual(p, q[, epsilon]) 2 | // 3 | // Test if points are almost equal by the margin of epsilon. 4 | // 5 | // Parameters 6 | // p 7 | // a point2 8 | // q 9 | // a point2 10 | // epsilon 11 | // optional number, default to affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return 15 | // a boolean 16 | // 17 | module.exports = require('../vec2/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/point3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.point3.almostEqual(p, q[, epsilon]) 2 | // 3 | // Test if points are almost equal by the margin of epsilon. 4 | // 5 | // Parameters 6 | // p 7 | // a point3 8 | // q 9 | // a point3 10 | // epsilon 11 | // optional number, default to affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return 15 | // a boolean 16 | // 17 | module.exports = require('../vec3/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/size3/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = function (s, ss) { 2 | // @affineplane.size3.equal(s, ss) 3 | // 4 | // Test if two sizes are strictly equal in value. 5 | // The size objects are allowed to have additional non-equal properties. 6 | // 7 | // Parameters: 8 | // s 9 | // a size3 10 | // ss 11 | // a size3 12 | // 13 | // Return: 14 | // a boolean 15 | // 16 | return s.w === ss.w && s.h === ss.h && s.d === ss.d 17 | } 18 | -------------------------------------------------------------------------------- /test/dist3/projectToPlane.test.js: -------------------------------------------------------------------------------- 1 | const dist3 = require('../../lib/dist3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: smoke', (t) => { 5 | const d = 4 6 | const planea = { a: 2, b: 0, x: 0, y: 0, z: -2 } 7 | const cameraa = { x: 1, y: 1, z: -4 } 8 | t.deepEqual( 9 | dist3.projectTo(d, planea, cameraa), 10 | 1, 11 | 'perspective halves and target scale halves again' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/orient2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | almostEqual: require('./almostEqual.test'), 4 | create: require('./create.test'), 5 | equal: require('./equal.test'), 6 | fromPolar: require('./fromPolar.test'), 7 | validate: require('./validate.test') 8 | } 9 | 10 | module.exports = (t) => { 11 | Object.keys(units).forEach((unitName) => { 12 | t.test('affineplane.orient2.' + unitName, units[unitName]) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/path2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | combine: require('./combine.test'), 4 | create: require('./create.test'), 5 | transitFrom: require('./transitFrom.test'), 6 | transitTo: require('./transitTo.test'), 7 | validate: require('./validate.test') 8 | } 9 | 10 | module.exports = (t) => { 11 | Object.keys(units).forEach((unitName) => { 12 | t.test('affineplane.path2.' + unitName, units[unitName]) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/helm2/fromArray.js: -------------------------------------------------------------------------------- 1 | module.exports = function (abxy) { 2 | // @affineplane.helm2.fromArray(abxy) 3 | // Create an affine similarity transform from 4-element array. 4 | // 5 | // Parameter 6 | // abxy 7 | // an array with four number elements [a, b, x, y] 8 | // 9 | // Return 10 | // a helm2, a similarity transform. 11 | // 12 | return { 13 | a: abxy[0], 14 | b: abxy[1], 15 | x: abxy[2], 16 | y: abxy[3] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/helm3/fromVector.js: -------------------------------------------------------------------------------- 1 | module.exports = (vec) => { 2 | // @affineplane.helm3.fromVector(vec) 3 | // 4 | // Create a helm3 transformation from a translation vector. 5 | // 6 | // Parameters: 7 | // vec 8 | // a vec3, the displacement vector 9 | // 10 | // Return: 11 | // a helm3 12 | // 13 | return { 14 | a: 1, 15 | b: 0, 16 | x: vec.x, 17 | y: vec.y, 18 | z: (vec.z ? vec.z : 0) // allow vec2 secretly 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/line2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.line2 2 | // 3 | // Directed line object with origin point in space and a spanning vector. 4 | // 5 | // A line2 is an object `{ origin: {x,y}, span: {x,y} }` 6 | // 7 | 8 | exports.at = require('./at') 9 | exports.create = require('./create') 10 | exports.fromPoints = require('./fromPoints') 11 | exports.intersection = require('./intersection') 12 | exports.normal = require('./normal') 13 | exports.validate = require('./validate') 14 | -------------------------------------------------------------------------------- /lib/segment2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.segment2 2 | // 3 | // Two-dimensional line segment. Represented by the segment start and end 4 | // points in an array of length two. 5 | // 6 | // Example: `[{ x: 0, y: 0 }, { x: 1, y: 2 }]` 7 | // 8 | 9 | exports.collide = require('./collide') 10 | exports.create = require('./create') 11 | exports.transitFrom = require('./transitFrom') 12 | exports.transitTo = require('./transitTo') 13 | exports.validate = require('./validate') 14 | -------------------------------------------------------------------------------- /test/dir2/copy.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dir2 = affineplane.dir2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: copy', (t) => { 6 | const dir = { x: 1, y: 0 } 7 | t.notEqual( 8 | dir2.copy(dir), 9 | dir, 10 | 'ensure different object' 11 | ) 12 | 13 | t.deepEqual( 14 | dir2.copy(dir), 15 | dir, 16 | 'ensure deep equality' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /test/path3/combine.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path3 = affineplane.path3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic combine', (t) => { 6 | const p0 = [{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }] 7 | const p1 = [{ x: 2, y: 2, z: 2 }] 8 | 9 | t.deepEqual( 10 | path3.combine(p0, p1), 11 | p0.concat(p1), 12 | 'should copy arrays together' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/ray3/invert.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: negate ray', (t) => { 5 | const r = { x: 1, y: 2, z: 3, dx: 4, dy: 5, dz: 6 } 6 | t.deepEqual( 7 | ray3.invert(r), 8 | { x: 1, y: 2, z: 3, dx: -4, dy: -5, dz: -6 }, 9 | 'should negate only span' 10 | ) 11 | 12 | t.deepEqual(ray3.negate(r), ray3.invert(r), 'should have alias') 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/segment2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | collide: require('./collide.test'), 4 | create: require('./create.test'), 5 | transitFrom: require('./transitFrom.test'), 6 | transitTo: require('./transitTo.test'), 7 | validate: require('./validate.test') 8 | } 9 | 10 | module.exports = (t) => { 11 | Object.keys(units).forEach((unitName) => { 12 | t.test('affineplane.segment2.' + unitName, units[unitName]) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/size2/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size2 = affineplane.size2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | t.deepEqual( 7 | size2.create(1, -2), 8 | { w: 1, h: 2 }, 9 | 'should be absolute value' 10 | ) 11 | 12 | t.deepEqual( 13 | size2.create(0, 0), 14 | { w: 0, h: 0 }, 15 | 'should allow zero' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/utils/almostEqual.js: -------------------------------------------------------------------------------- 1 | const almost = require('./almost') 2 | 3 | module.exports = function (actual, expected, message) { 4 | // Custom tape.js assertion. 5 | // 6 | // Detects almost equality of numbers, points, and vectors. 7 | // 8 | const assertion = almost(actual, expected) 9 | 10 | this._assert(assertion, { 11 | message: message || 'should be almost equal', 12 | operator: 'almostEqual', 13 | actual, 14 | expected 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /lib/epsilon.js: -------------------------------------------------------------------------------- 1 | // @affineplane.epsilon 2 | // 3 | // Default margin for non-strict numeric equality. 4 | // For example `0.0000000001`. 5 | // 6 | 7 | // Default epsilon to use when coping with floating point arithmetics. 8 | // JavaScript floating point numbers have 52 bits in mantissa (IEEE-754). 9 | // That is about 16 base10 numbers. Therefore the epsilon should be 10 | // much larger than 1 * 10^-16. Let say 1 * 10^-10 is a good one. 11 | module.exports = 0.0000000001 12 | -------------------------------------------------------------------------------- /lib/path2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.path2 2 | // 3 | // Two-dimensional path; Array of point2; Open sequence of points; 4 | // Does not form a polygon but a sequence of line segments. 5 | // 6 | // Example: `[{ x, y }, { x, y }, ...]` 7 | // 8 | 9 | exports.combine = require('./combine') 10 | exports.create = require('./create') 11 | exports.transitFrom = require('./transitFrom') 12 | exports.transitTo = require('./transitTo') 13 | exports.validate = require('./validate') 14 | -------------------------------------------------------------------------------- /lib/point3/distanceToPlane.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, plane) => { 2 | // @affineplane.point3.distanceToPlane(p, plane) 3 | // 4 | // Euclidean distance between point and plane. 5 | // 6 | // Parameters 7 | // p 8 | // a point3 9 | // plane 10 | // a plane3 11 | // 12 | // Return 13 | // a number, a scalar1, a dist3, a distance 14 | // 15 | 16 | // Assert plane3 is parallel to xy-plane 17 | 18 | return Math.abs(plane.z - p.z) 19 | } 20 | -------------------------------------------------------------------------------- /lib/sphere3/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (c, d) => { 2 | // @affineplane.sphere3.equal(c, d) 3 | // 4 | // Test if two spheres are strictly equal in radius and position. 5 | // See affineplane.sphere3.almostEqual for loose comparison. 6 | // 7 | // Parameters 8 | // c 9 | // a sphere3 10 | // d 11 | // a sphere3 12 | // 13 | // Return 14 | // a boolean 15 | // 16 | return c.x === d.x && c.y === d.y && c.z === d.z && c.r === d.r 17 | } 18 | -------------------------------------------------------------------------------- /test/dir2/toPolar.test.js: -------------------------------------------------------------------------------- 1 | const dir2 = require('../../index').dir2 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: dir to polar angle', (t) => { 6 | t.almostEqual( 7 | dir2.toPolar(dir2.fromPolar(PI / 2)), 8 | PI / 2, 9 | 'symmetry' 10 | ) 11 | 12 | t.almostEqual( 13 | dir2.toPolar({ x: 1, y: 1 }), 14 | dir2.toAngle({ x: 1, y: 1 }), 15 | 'alias' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/dir3/copy.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dir3 = affineplane.dir3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: copy', (t) => { 6 | const dir = { x: 1, y: 0, z: 0 } 7 | t.notEqual( 8 | dir3.copy(dir), 9 | dir, 10 | 'ensure different object' 11 | ) 12 | 13 | t.deepEqual( 14 | dir3.copy(dir), 15 | dir, 16 | 'ensure deep equality' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /test/plane2/getScale.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic scales', (t) => { 5 | t.almostEqual( 6 | plane2.getScale({ a: 1, b: 0, x: 0, y: 0 }), 7 | 1, 8 | 'trivial' 9 | ) 10 | 11 | t.almostEqual( 12 | plane2.getScale({ a: 0, b: -2, x: 4, y: 6 }), 13 | 2, 14 | 'should be invariant of rotation and sign' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/plane2/invert.test.js: -------------------------------------------------------------------------------- 1 | // Light-weight tests because 2 | // plane2.invert is helm2.invert 3 | // which has wider test suite. 4 | // 5 | const plane2 = require('../../lib/plane2') 6 | 7 | module.exports = (ts) => { 8 | ts.test('case: smoke', (t) => { 9 | t.almostEqual( 10 | plane2.invert({ a: 1, b: 0, x: 0, y: 0 }), 11 | { a: 1, b: 0, x: 0, y: 0 }, 12 | 'identity does not change under inversion' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/sphere2/collide.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic collide', (t) => { 5 | t.true( 6 | sphere2.collide({ x: 0, y: 0, r: 0 }, { x: 0, y: 0, r: 0 }), 7 | 'zero spheres collide' 8 | ) 9 | 10 | t.false( 11 | sphere2.collide({ x: 1, y: 0, r: 0 }, { x: 0, y: 0, r: 0 }), 12 | 'offset zero spheres do not collide' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/utils/notAlmostEqual.js: -------------------------------------------------------------------------------- 1 | const almost = require('./almost') 2 | 3 | module.exports = function (actual, expected, message) { 4 | // Custom tape.js assertion. 5 | // 6 | const actualValue = actual 7 | const assertion = almost(actualValue, expected) 8 | 9 | this._assert(!assertion, { 10 | message: message || 'should not be almost equal', 11 | operator: 'notAlmostEqual', 12 | actual: actualValue, 13 | expected: 'not ' + expected 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /lib/circle3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.almostEqual(c, d[, tolerance]) 2 | // 3 | // Test if two circles are almost equal by the margin of tolerance. 4 | // 5 | // Parameters 6 | // c 7 | // a circle3 8 | // d 9 | // a circle3 10 | // tolerance 11 | // optional number, default to affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return 15 | // a boolean 16 | // 17 | module.exports = require('../sphere3/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/line2/fromPoints.js: -------------------------------------------------------------------------------- 1 | const diff = require('../point2/difference') 2 | 3 | module.exports = (p, q) => { 4 | // @affineplane.line2.fromPoints(p, q) 5 | // 6 | // Create a line from two points 7 | // with a spanning vector from p to q. 8 | // 9 | // Parameters: 10 | // p 11 | // a point2 12 | // q 13 | // a point2 14 | // 15 | // Return 16 | // a line2 17 | // 18 | return { 19 | origin: p, 20 | span: diff(p, q) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/line3/fromPoints.js: -------------------------------------------------------------------------------- 1 | const diff = require('../point3/difference') 2 | 3 | module.exports = (p, q) => { 4 | // @affineplane.line3.fromPoints(p, q) 5 | // 6 | // Create a line from two points 7 | // with a spanning vector from p to q. 8 | // 9 | // Parameters: 10 | // p 11 | // a point3 12 | // q 13 | // a point3 14 | // 15 | // Return 16 | // a line3 17 | // 18 | return { 19 | origin: p, 20 | span: diff(p, q) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/path2/validate.js: -------------------------------------------------------------------------------- 1 | const validatePoint = require('../point2/validate') 2 | 3 | module.exports = (p) => { 4 | // @affineplane.path2.validate(p) 5 | // 6 | // Check if the object is a valid path2. 7 | // A valid path2 is an array of valid point2 objects. 8 | // 9 | // Parameter 10 | // p 11 | // an object 12 | // 13 | // Return 14 | // a boolean, true if valid 15 | // 16 | return Array.isArray(p) && p.every(point => validatePoint(point)) 17 | } 18 | -------------------------------------------------------------------------------- /lib/path3/validate.js: -------------------------------------------------------------------------------- 1 | const validatePoint = require('../point3/validate') 2 | 3 | module.exports = (p) => { 4 | // @affineplane.path3.validate(p) 5 | // 6 | // Check if the object is a valid path3. 7 | // A valid path3 is an array of valid point3 objects. 8 | // 9 | // Parameter 10 | // p 11 | // an object 12 | // 13 | // Return 14 | // a boolean, true if valid 15 | // 16 | return Array.isArray(p) && p.every(point => validatePoint(point)) 17 | } 18 | -------------------------------------------------------------------------------- /lib/size2/scaleBy.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz, multiplier) => { 2 | // @affineplane.size2.scaleBy(sz, multiplier) 3 | // 4 | // Scale and preserve aspect ratio. Multiplies all dimensions uniformly. 5 | // 6 | // Parameters: 7 | // sz 8 | // a size2 9 | // multiplier 10 | // a number 11 | // 12 | // Return: 13 | // a size2 14 | // 15 | return { 16 | w: Math.abs(sz.w * multiplier), 17 | h: Math.abs(sz.h * multiplier) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/vec2/transformBy.js: -------------------------------------------------------------------------------- 1 | module.exports = function (vec, tr) { 2 | // @affineplane.vec2.transformBy(vec, tr) 3 | // 4 | // Transform a vector. Translation does not affect the vector. 5 | // 6 | // Parameters 7 | // vec 8 | // a vec2 9 | // tr 10 | // a helm2 11 | // 12 | // Return 13 | // a vec2, the transformed vector 14 | // 15 | return { 16 | x: tr.a * vec.x - tr.b * vec.y, 17 | y: tr.b * vec.x + tr.a * vec.y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/angle/degToRad.test.js: -------------------------------------------------------------------------------- 1 | const angle = require('../../index').angle 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic radToDeg', (t) => { 6 | t.equal(angle.degToRad(90), PI / 2, 'right angle') 7 | t.equal(angle.degToRad(-180), -PI, 'allow negative') 8 | t.equal(angle.degToRad(720), PI * 4, 'allow value over limit') 9 | t.equal(angle.degToRad(-540), -3 * PI, 'allow value below limit') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/angle/radToDeg.test.js: -------------------------------------------------------------------------------- 1 | const angle = require('../../index').angle 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic radToDeg', (t) => { 6 | t.equal(angle.radToDeg(PI / 2), 90, 'right angle') 7 | t.equal(angle.radToDeg(-PI), -180, 'allow negative') 8 | t.equal(angle.radToDeg(PI * 4), 720, 'allow value over limit') 9 | t.equal(angle.radToDeg(-3 * PI), -540, 'allow value below limit') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/box2/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const box2 = require('../../lib/box2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: tolerance', (t) => { 5 | const p = { a: 1, b: 0, x: 0, y: 0, w: 1, h: 2 } 6 | const q = { a: 1, b: 0, x: 1, y: 0, w: 2, h: 2 } 7 | t.false(box2.almostEqual(p, q, 1), 'above tolerance') 8 | t.true(box2.almostEqual(p, q, 2), 'at tolerance') 9 | t.true(box2.almostEqual(p, q, 3), 'below tolerance') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/helm3/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const helm3 = require('../../lib/helm3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic helm3 transit from plane', (t) => { 5 | const tr = { a: 2, b: 0, x: 2, y: 3, z: 5 } 6 | const source = { a: 1, b: 0, x: 2, y: 4, z: 6 } 7 | t.deepEqual( 8 | helm3.transitFrom(tr, source), 9 | { a: 2, b: 0, x: 2, y: 3, z: 5 }, 10 | 'plane translation does not affect' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/plane2/difference.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic difference', (t) => { 5 | const source = { a: 1, b: 0, x: 1, y: 1 } 6 | const target = { a: 2, b: 0, x: 2, y: 2 } 7 | 8 | t.almostEqual( 9 | plane2.between(source, target), 10 | { a: 0.5, b: 0, x: 0, y: 0 }, 11 | 'transformation that would map target to source' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/vec2/fromPolar.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic fromPolar', (t) => { 6 | t.almostEqual( 7 | vec2.fromPolar(2, 0), 8 | { x: 2, y: 0 }, 9 | 'zero angle' 10 | ) 11 | 12 | t.almostEqual( 13 | vec2.fromPolar(2, Math.PI / 2), 14 | { x: 0, y: 2 }, 15 | 'angle of +90deg' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/vec3/sum.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic sum', (t) => { 5 | t.almostEqual(vec3.sum([ 6 | { x: 1, y: 2, z: 3 }, 7 | { x: 2, y: 3, z: 1 }, 8 | { x: 3, y: 1, z: 2 } 9 | ]), { x: 6, y: 6, z: 6 }) 10 | 11 | t.end() 12 | }) 13 | 14 | ts.test('case: empty array', (t) => { 15 | t.almostEqual(vec3.sum([]), { x: 0, y: 0, z: 0 }) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lib/orient2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.orient2 2 | // 3 | // Orientation in 2D. Represented by an object `{ a, b }`. 4 | // 5 | exports.almostEqual = require('./almostEqual') 6 | exports.create = require('./create') 7 | exports.equal = require('./equal') 8 | exports.fromPolar = require('./fromPolar') 9 | exports.fromVector = exports.fromPolar 10 | exports.transitFrom = require('./transitFrom') 11 | exports.transitTo = require('./transitTo') 12 | exports.validate = require('./validate') 13 | -------------------------------------------------------------------------------- /lib/point3/translate.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, vec) => { 2 | // @affineplane.point3.translate(p, vec) 3 | // @affineplane.point3.translateBy 4 | // 5 | // Translate the point by the given vector. 6 | // 7 | // Parameters: 8 | // p 9 | // a point3 10 | // vec 11 | // a vec3 or vec2 12 | // 13 | // Return 14 | // a point3 15 | // 16 | return { 17 | x: p.x + vec.x, 18 | y: p.y + vec.y, 19 | z: p.z + (vec.z ? vec.z : 0) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/rot2/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.rot2 2 | // 3 | // Rotation in 2D. Represented by object `{ a, b }`. 4 | // 5 | // Rotation differs from orientation in the manner that 6 | // where orientation is a static rotational position of an object, 7 | // rotation is dynamic transform of an object. 8 | // Therefore a change of basis does not affect rotation but 9 | // it does affect orientation. 10 | // 11 | exports.create = require('./create') 12 | exports.validate = require('./validate') 13 | -------------------------------------------------------------------------------- /lib/segment3/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.segment3 2 | // 3 | // Three-dimensional line segment. Represented by the segment start and end 4 | // points in an array of length two. 5 | // 6 | // Example: `[{ x: 0, y: 0, z: 0 }, { x: 1, y: 2, z: 3 }]` 7 | // 8 | 9 | exports.create = require('./create') 10 | exports.toVector = require('./toVector') 11 | exports.transitFrom = require('./transitFrom') 12 | exports.transitTo = require('./transitTo') 13 | exports.validate = require('./validate') 14 | -------------------------------------------------------------------------------- /lib/size3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (width, height, depth) => { 2 | // @affineplane.size3.create(width, height, depth) 3 | // 4 | // Create a size3 object. 5 | // 6 | // Parameters: 7 | // width 8 | // a number 9 | // height 10 | // a number 11 | // depth 12 | // a number 13 | // 14 | // Return 15 | // a size3 16 | // 17 | return { 18 | w: Math.abs(width), 19 | h: Math.abs(height), 20 | d: Math.abs(depth) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/plane3/invert.test.js: -------------------------------------------------------------------------------- 1 | // Light-weight tests because 2 | // plane3.invert is helm3.invert 3 | // which has wider test suite. 4 | // 5 | const plane3 = require('../../lib/plane3') 6 | 7 | module.exports = (ts) => { 8 | ts.test('case: smoke', (t) => { 9 | t.almostEqual( 10 | plane3.invert({ a: 1, b: 0, x: 0, y: 0, z: 0 }), 11 | { a: 1, b: 0, x: 0, y: 0, z: 0 }, 12 | 'identity does not change under inversion' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/box3/getBasis.js: -------------------------------------------------------------------------------- 1 | module.exports = (box) => { 2 | // @affineplane.box3.getBasis(box) 3 | // 4 | // Get the inner basis of the box. 5 | // The scale of the resulting basis is always 1. 6 | // 7 | // Parameters: 8 | // box 9 | // a box3 in the reference basis. 10 | // 11 | // Return 12 | // a plane3 in the reference basis. 13 | // 14 | return { 15 | a: box.a, 16 | b: box.b, 17 | x: box.x, 18 | y: box.y, 19 | z: box.z 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/circle3/transitTo.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.transitTo(circle, target) 2 | // 3 | // Transit a circle3 to the target basis 4 | // from the reference basis. 5 | // 6 | // Parameters: 7 | // circle 8 | // a circle3 in the source basis. 9 | // source 10 | // a plane3, the source basis, represented 11 | // .. in the reference basis. 12 | // 13 | // Return: 14 | // a circle3, represented in the reference basis. 15 | // 16 | module.exports = require('../sphere3/transitTo') 17 | -------------------------------------------------------------------------------- /test/box2/getAngle.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const box2 = affineplane.box2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic angle', (t) => { 6 | const b = { a: 1, b: 0, x: 0, y: 0, w: 10, h: 6 } 7 | t.almostEqual(box2.getAngle(b), 0, 'should have zero rotation') 8 | 9 | const bb = { a: 0, b: 1, x: 200, y: 200, w: 10, h: 6 } 10 | t.almostEqual(box2.getAngle(bb), Math.PI / 2, 'should 90 deg') 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/plane2/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic plane2 transit from another plane', (t) => { 5 | const plane = { a: 2, b: 0, x: 2, y: 3 } 6 | const source = { a: 1, b: 0, x: 2, y: 4 } 7 | t.deepEqual( 8 | plane2.transitFrom(plane, source), 9 | { a: 2, b: 0, x: 4, y: 7 }, 10 | 'scale, rotation, and translation combined' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/plane3/difference.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic difference', (t) => { 5 | const source = { a: 1, b: 0, x: 1, y: 1, z: 1 } 6 | const target = { a: 2, b: 0, x: 2, y: 2, z: 2 } 7 | 8 | t.almostEqual( 9 | plane3.between(source, target), 10 | { a: 0.5, b: 0, x: 0, y: 0, z: 0 }, 11 | 'transformation that maps target to source' 12 | ) 13 | 14 | t.end() 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/plane3/getScale.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic scales', (t) => { 5 | t.almostEqual( 6 | plane3.getScale({ a: 1, b: 0, x: 0, y: 0, z: 0 }), 7 | 1, 8 | 'trivial' 9 | ) 10 | 11 | t.almostEqual( 12 | plane3.getScale({ a: 0, b: -2, x: 4, y: 6, z: 8 }), 13 | 2, 14 | 'should be invariant of rotation and sign' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/point2/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: margin', (t) => { 5 | const p = { x: 0, y: 0 } 6 | const q = { x: 3, y: 3 } 7 | 8 | t.false(point2.almostEqual(p, q, 1), 'should be way too different') 9 | t.false(point2.almostEqual(p, q, 5), 'should be just different enough') 10 | t.true(point2.almostEqual(p, q, 6), 'should be within tolerance') 11 | 12 | t.end() 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /test/point2/direction.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic difference', (t) => { 5 | t.deepEqual(point2.direction( 6 | { x: 3, y: 0 }, 7 | { x: 3, y: 3 } 8 | ), { x: 0, y: 1 }, 'should point pos y') 9 | 10 | t.deepEqual(point2.direction( 11 | { x: 3, y: 3 }, 12 | { x: 3, y: 3 } 13 | ), { x: 1, y: 0 }, 'should default when no dir') 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/size3/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size3 = affineplane.size3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | t.deepEqual( 7 | size3.create(1, -2, -3), 8 | { w: 1, h: 2, d: 3 }, 9 | 'should be absolute value' 10 | ) 11 | 12 | t.deepEqual( 13 | size3.create(0, 0, 0), 14 | { w: 0, h: 0, d: 0 }, 15 | 'should allow zero' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/sphere2/atCenter.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../index').sphere2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic sphere center', (t) => { 5 | t.deepEqual( 6 | sphere2.atCenter({ x: 0, y: 0, r: 0 }), 7 | { x: 0, y: 0 }, 8 | 'trivial zero' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere2.atCenter({ x: 2, y: 2, r: 2 }), 13 | { x: 2, y: 2 }, 14 | 'should have correct props' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/sphere2/size.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../index').sphere2 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic sphere size', (t) => { 5 | t.deepEqual( 6 | sphere2.size({ x: 0, y: 0, r: 0 }), 7 | { w: 0, h: 0 }, 8 | 'trivial null circle' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere2.size({ x: 2, y: 2, r: 2 }), 13 | { w: 4, h: 4 }, 14 | 'should have size double the radius' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/vec2/dot.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: zeroes and ones', (t) => { 6 | t.equal( 7 | vec2.dot( 8 | { x: 0, y: 0 }, 9 | { x: 0, y: 0 } 10 | ), 11 | 0 12 | ) 13 | 14 | t.equal( 15 | vec2.dot( 16 | { x: 1, y: 1 }, 17 | { x: 1, y: 1 } 18 | ), 19 | 2 20 | ) 21 | 22 | t.end() 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /test/vec2/inverse.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: vector negation', (t) => { 6 | t.almostEqual( 7 | vec2.invert({ x: 0, y: 0 }), 8 | { x: 0, y: 0 }, 9 | 'invert zero vector' 10 | ) 11 | 12 | t.almostEqual( 13 | vec2.negate({ x: 1, y: -1 }), 14 | { x: -1, y: 1 }, 15 | 'negate ones' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /lib/circle3/transitFrom.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.transitFrom(circle, source) 2 | // 3 | // Transit a circle3 from the source basis 4 | // to the reference basis. 5 | // 6 | // Parameters: 7 | // circle 8 | // a circle3 in the source basis. 9 | // source 10 | // a plane3, the source basis, represented 11 | // .. in the reference basis. 12 | // 13 | // Return: 14 | // a circle3, represented in the reference basis. 15 | // 16 | module.exports = require('../sphere3/transitFrom') 17 | -------------------------------------------------------------------------------- /lib/dist3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist3.almostEqual(c, d[, tolerance]) 2 | // 3 | // Test if distances c, d are equal by the margin of tolerance. 4 | // 5 | // Parameters 6 | // c 7 | // a number, the dist3 8 | // d 9 | // a number, the dist3 10 | // tolerance 11 | // optional number, default is affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return 15 | // a boolean 16 | // 17 | module.exports = require('../scalar1/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/point2/difference.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, q) => { 2 | // @affineplane.point2.difference(p, q) 3 | // @affineplane.point2.diff 4 | // @affineplane.point2.delta 5 | // @affineplane.point2.vectorTo 6 | // 7 | // A vector from point p to point q. 8 | // 9 | // Parameters: 10 | // p 11 | // a point2 12 | // q 13 | // a point2 14 | // 15 | // Return 16 | // a vec2 17 | // 18 | return { 19 | x: q.x - p.x, 20 | y: q.y - p.y 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/point3/round.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic round', (t) => { 5 | t.deepEqual( 6 | point3.round({ x: 0, y: 1, z: 2 }), 7 | { x: 0, y: 1, z: 2 }, 8 | 'already integer' 9 | ) 10 | 11 | t.deepEqual( 12 | point3.round({ x: 0.2, y: 1.4, z: 1.51 }), 13 | { x: 0, y: 1, z: 2 }, 14 | 'should round to nearest integer' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lib/circle3/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (x, y, z, r) => { 2 | // @affineplane.circle3.create(x, y, z, r) 3 | // 4 | // Create a circle object in 3D. The circle is a flat round shape 5 | // parallel to xy-plane. 6 | // 7 | // Parameters: 8 | // x 9 | // a number 10 | // y 11 | // a number 12 | // z 13 | // a number 14 | // r 15 | // a number, the radius 16 | // 17 | // Return 18 | // a circle3 19 | // 20 | return { x, y, z, r } 21 | } 22 | -------------------------------------------------------------------------------- /lib/dir2/projectToPlane.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dir2.projectToPlane(dir, plane) 2 | // @affineplane.dir2.projectTo 3 | // 4 | // Project a 2D direction onto a 2D plane. Perspective does not 5 | // affect the direction. 6 | // 7 | // Parameters: 8 | // dir 9 | // a dir2 in the reference basis. 10 | // plane 11 | // a plane3 in the reference basis. 12 | // .. The image plane. 13 | // 14 | // Return: 15 | // a dir2 on the image plane. 16 | // 17 | module.exports = require('./transitTo') 18 | -------------------------------------------------------------------------------- /lib/dist2/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist2.almostEqual(c, d[, tolerance]) 2 | // 3 | // Test if distances c, d are almost equal by the margin of tolerance. 4 | // 5 | // Parameters 6 | // c 7 | // a number, the dist2 8 | // d 9 | // a number, the dist2 10 | // tolerance 11 | // optional number, default is affineplane.epsilon. 12 | // .. Set to 0 for strict comparison. 13 | // 14 | // Return 15 | // a boolean 16 | // 17 | module.exports = require('../scalar1/almostEqual') 18 | -------------------------------------------------------------------------------- /lib/point2/translate.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, vec) => { 2 | // @affineplane.point2.translate(p, vec) 3 | // @affineplane.point2.move 4 | // 5 | // Translate the point by the given vector. 6 | // See affineplane.point2.offset to translate by scalars. 7 | // 8 | // Parameters: 9 | // p 10 | // a point2 11 | // vec 12 | // a vec2 13 | // 14 | // Return 15 | // a point2 16 | // 17 | return { 18 | x: p.x + vec.x, 19 | y: p.y + vec.y 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/line2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | at: require('./at.test'), 4 | create: require('./create.test'), 5 | fromPoints: require('./fromPoints.test'), 6 | intersection: require('./intersection.test'), 7 | normal: require('./normal.test'), 8 | validate: require('./validate.test') 9 | } 10 | 11 | module.exports = (t) => { 12 | Object.keys(units).forEach((unitName) => { 13 | t.test('affineplane.line2.' + unitName, units[unitName]) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/orient2/fromPolar.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const orient2 = affineplane.orient2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic fromPolar', (t) => { 6 | t.almostEqualOrient( 7 | orient2.fromPolar(0), 8 | { a: 1, b: 0 }, 9 | 'zero angle' 10 | ) 11 | 12 | t.almostEqualOrient( 13 | orient2.fromPolar(Math.PI / 2), 14 | { a: 0, b: 1 }, 15 | 'angle of +90deg' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/point2/offset.test.js: -------------------------------------------------------------------------------- 1 | const point2 = require('../../lib/point2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic offset', (t) => { 5 | t.deepEqual( 6 | point2.offset({ x: 0, y: 0 }, 1, 1), 7 | { x: 1, y: 1 }, 8 | 'zero point should move by unit' 9 | ) 10 | 11 | t.deepEqual( 12 | point2.offset({ x: 3, y: -3 }, 1, 1), 13 | { x: 4, y: -2 }, 14 | 'non zero point should move by unit' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lib/point3/distance.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, q) => { 2 | // @affineplane.point3.distance(p, q) 3 | // 4 | // Euclidean distance between two points. 5 | // 6 | // Parameters 7 | // p 8 | // a point3 9 | // q 10 | // a point3 11 | // 12 | // Return 13 | // a number, a distance from p to q (= distance from q to p) 14 | // 15 | const dx = q.x - p.x 16 | const dy = q.y - p.y 17 | const dz = q.z - p.z 18 | 19 | return Math.sqrt(dx * dx + dy * dy + dz * dz) 20 | } 21 | -------------------------------------------------------------------------------- /lib/ray3/equal.js: -------------------------------------------------------------------------------- 1 | module.exports = (r, rr) => { 2 | // @affineplane.ray3.equal(r, rr) 3 | // 4 | // Test if rays are strictly equal in position and direction. 5 | // 6 | // Parameters 7 | // r 8 | // a ray3 9 | // rr 10 | // a ray3 11 | // 12 | // Return 13 | // a boolean 14 | // 15 | return ( 16 | r.x === rr.x && 17 | r.y === rr.y && 18 | r.z === rr.z && 19 | r.dx === rr.dx && 20 | r.dy === rr.dy && 21 | r.dz === rr.dz 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /lib/scalar1/validate.js: -------------------------------------------------------------------------------- 1 | module.exports = (s) => { 2 | // @affineplane.scalar1.validate(s) 3 | // 4 | // Check if the argument is a valid scalar1. 5 | // Valid scalar1 is a number and not NaN. 6 | // 7 | // Parameter 8 | // s 9 | // a value 10 | // 11 | // Return 12 | // a boolean, true if valid scalar1 13 | // 14 | if (typeof s !== 'number') { 15 | return false 16 | } 17 | 18 | if (Number.isNaN(s)) { 19 | return false 20 | } 21 | 22 | return true 23 | } 24 | -------------------------------------------------------------------------------- /lib/sphere2/translate.js: -------------------------------------------------------------------------------- 1 | module.exports = (c, vec) => { 2 | // @affineplane.sphere2.translate(c, vec) 3 | // 4 | // Translate the circle by the vector. Does not affect radius. 5 | // See affineplane.sphere2.offset to translate by scalars. 6 | // 7 | // Parameters: 8 | // c 9 | // a sphere2 10 | // vec 11 | // a vec2 12 | // 13 | // Return 14 | // a sphere2 15 | // 16 | return { 17 | x: c.x + vec.x, 18 | y: c.y + vec.y, 19 | r: c.r 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/vec2/cross.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, w) => { 2 | // @affineplane.vec2.cross(v, w) 3 | // 4 | // The magnitude of cross product of two 2D vectors. While in 3D, 5 | // the cross product returns a perpendicular vector, in 2D we must 6 | // settle for a scalar result, the length of that 3D vector. 7 | // 8 | // Parameters: 9 | // v 10 | // a vec2 11 | // w 12 | // a vec2 13 | // 14 | // Return 15 | // a number 16 | // 17 | return v.x * w.y - v.y * w.x 18 | } 19 | -------------------------------------------------------------------------------- /test/box3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const box3 = require('../../lib/box3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: tolerance', (t) => { 5 | const p = { a: 1, b: 0, x: 0, y: 0, z: 0, w: 1, h: 2, d: 3 } 6 | const q = { a: 1, b: 0, x: 1, y: 0, z: 0, w: 1, h: 2, d: 2 } 7 | t.false(box3.almostEqual(p, q, 1), 'above tolerance') 8 | t.true(box3.almostEqual(p, q, 2), 'at tolerance') 9 | t.true(box3.almostEqual(p, q, 3), 'below tolerance') 10 | 11 | t.end() 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/dir2/fromVector.test.js: -------------------------------------------------------------------------------- 1 | const dir2 = require('../../index').dir2 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: dir from vector', (t) => { 6 | t.almostEqual( 7 | dir2.fromVector({ x: 0, y: 0 }), 8 | { x: 1, y: 0 }, 9 | 'arbitrary direction' 10 | ) 11 | 12 | t.almostEqual( 13 | dir2.fromVector({ x: 1, y: 1 }), 14 | dir2.fromAngle(PI / 4), 15 | 'allow non-unit vector' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/line2/create.test.js: -------------------------------------------------------------------------------- 1 | const line2 = require('../../lib/line2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create valid line2', (t) => { 5 | const origin = { x: 2, y: 1 } 6 | const span = { x: 3, y: 3 } 7 | t.deepEqual( 8 | line2.create(origin, span), 9 | { origin, span }, 10 | 'correct format' 11 | ) 12 | 13 | t.ok( 14 | line2.validate(line2.create(origin, span)), 15 | 'ensure valid' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/plane3/orientation.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: plane orientation', (t) => { 5 | t.deepEqual( 6 | plane3.orientation({ a: 1, b: 0, x: 0, y: 0, z: 0 }), 7 | { a: 1, b: 0 }, 8 | 'trivial' 9 | ) 10 | 11 | t.deepEqual( 12 | plane3.orientation({ a: 0, b: 2, x: 0, y: 0, z: 0 }), 13 | { a: 0, b: 1 }, 14 | 'should make unitary' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/point3/equal.test.js: -------------------------------------------------------------------------------- 1 | const point3 = require('../../lib/point3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic equality', (t) => { 5 | t.ok(point3.equal( 6 | { x: 0, y: 1, z: 0 }, 7 | { x: 0, y: 1, z: 0 } 8 | )) 9 | t.notOk(point3.equal( 10 | { x: 0, y: 1, z: 0 }, 11 | { x: 0, y: 0, z: 0 } 12 | )) 13 | t.notOk(point3.equal( 14 | { x: 0, y: 0, z: 0 }, 15 | { x: 0, y: 0, z: 1 } 16 | )) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/vec3/fromPolar.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic polar coords', (t) => { 6 | t.almostEqual( 7 | vec3.fromPolar(2, PI / 2, 1), 8 | { x: 0, y: 2, z: 1 } 9 | ) 10 | 11 | t.end() 12 | }) 13 | 14 | ts.test('case: unset depth', (t) => { 15 | t.almostEqual( 16 | vec3.fromPolar(2, PI / 2), 17 | { x: 0, y: 2, z: 0 } 18 | ) 19 | 20 | t.end() 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /lib/box2/offset.js: -------------------------------------------------------------------------------- 1 | module.exports = (box, dx, dy) => { 2 | // @affineplane.box2.offset(box, dx, dy) 3 | // 4 | // Move the box horizontally and vertically. 5 | // 6 | // Parameters: 7 | // box 8 | // a box2 9 | // dx 10 | // a number 11 | // dy 12 | // a number 13 | // 14 | // Return 15 | // a box2 16 | // 17 | return { 18 | a: box.a, 19 | b: box.b, 20 | x: box.x + dx, 21 | y: box.y + dy, 22 | w: box.w, 23 | h: box.h 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/vec2/fromPolar.js: -------------------------------------------------------------------------------- 1 | module.exports = (radius, direction) => { 2 | // @affineplane.vec2.fromPolar(radius, direction) 3 | // 4 | // Create a vector from polar coordinates. 5 | // 6 | // Parameters 7 | // radius 8 | // a number, radial length from the origin 9 | // direction 10 | // a number, angle in radians 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | return { 16 | x: radius * Math.cos(direction), 17 | y: radius * Math.sin(direction) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/plane2/copy.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic copy', (t) => { 5 | t.deepEqual( 6 | plane2.copy({ a: 1, b: 2, x: 3, y: 4 }), 7 | { a: 1, b: 2, x: 3, y: 4 }, 8 | 'should have same content' 9 | ) 10 | 11 | const p = { a: 1, b: 2, x: 3, y: 4 } 12 | t.notEqual( 13 | plane2.clone(p), 14 | p, 15 | 'should not be the same object' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/plane3/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic plane3 transit from another plane', (t) => { 5 | const plane = { a: 2, b: 0, x: 2, y: 3, z: 5 } 6 | const source = { a: 1, b: 0, x: 2, y: 4, z: 6 } 7 | t.deepEqual( 8 | plane3.transitFrom(plane, source), 9 | { a: 2, b: 0, x: 4, y: 7, z: 11 }, 10 | 'scale, rotation, and translation combined' 11 | ) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/quat4/hamilton.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const quat4 = affineplane.quat4 3 | const SQ2 = Math.sqrt(2) 4 | 5 | module.exports = (ts) => { 6 | ts.test('case: basic hamilton product', (t) => { 7 | t.deepEqual( 8 | quat4.hamilton( 9 | { a: 0, b: SQ2, c: SQ2, d: 0 }, 10 | { a: 0, b: 0, c: 0, d: 2 } 11 | ), 12 | { a: 0, b: 2 * SQ2, c: -2 * SQ2, d: 0 }, 13 | 'hamilton of two 3D vectors' 14 | ) 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /test/size2/scaleBy.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size2 = affineplane.size2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | const s = { w: 1, h: 2 } 7 | t.deepEqual( 8 | size2.scaleBy(s, -1), 9 | { w: 1, h: 2 }, 10 | 'should stay absolute' 11 | ) 12 | 13 | t.deepEqual( 14 | size2.scaleBy(s, 2), 15 | { w: 2, h: 4 }, 16 | 'should scale uniformly' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /lib/dir2/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dir2.almostEqual(d, dd[, epsilon]) 2 | // 3 | // Test if directions are almost equal by the margin of epsilon. 4 | // The directions are compared as two unit vectors. 5 | // 6 | // Parameters 7 | // d 8 | // a dir2 9 | // dd 10 | // a dir2 11 | // epsilon 12 | // Optional number, default to affineplane.epsilon. 13 | // Set to 0 for strict comparison. 14 | // 15 | // Return 16 | // a boolean 17 | // 18 | module.exports = require('../vec2/almostEqual') 19 | -------------------------------------------------------------------------------- /lib/dir3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dir3.almostEqual(d, dd[, epsilon]) 2 | // 3 | // Test if directions are almost equal by the margin of epsilon. 4 | // The directions are compared as two unit vectors. 5 | // 6 | // Parameters 7 | // d 8 | // a dir3 9 | // dd 10 | // a dir3 11 | // epsilon 12 | // Optional number, default to affineplane.epsilon. 13 | // Set to 0 for strict comparison. 14 | // 15 | // Return 16 | // a boolean 17 | // 18 | module.exports = require('../vec3/almostEqual') 19 | -------------------------------------------------------------------------------- /lib/point2/offset.js: -------------------------------------------------------------------------------- 1 | module.exports = (p, dx, dy) => { 2 | // @affineplane.point2.offset(p, dx, dy) 3 | // 4 | // Offset a point by scalars dx dy. 5 | // 6 | // Parameters: 7 | // p 8 | // a point2 9 | // dx 10 | // a number, an offset along x-axis. 11 | // dy 12 | // a number, an offset along y-axis. 13 | // 14 | // Return 15 | // a point2, translated by the vector { x: dx, y: dy } 16 | // 17 | return { 18 | x: p.x + dx, 19 | y: p.y + dy 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/circle3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const fine = require('../../index') // should be exported 2 | const circle3 = fine.circle3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: margin', (t) => { 6 | const p = { x: 0, y: 0, z: 0, r: 0 } 7 | const q = { x: 3, y: 3, z: 3, r: 3 } 8 | t.false(circle3.almostEqual(p, q, 1)) 9 | t.false(circle3.almostEqual(p, q, 11)) 10 | t.true(circle3.almostEqual(p, q, 12)) 11 | t.true(circle3.almostEqual(p, q, 13)) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/dist3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const dist3 = affineplane.dist3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic equivalence', (t) => { 6 | t.ok(dist3.equal(0, 0), 'strict equal') 7 | t.notOk(dist3.equal(-2, 2), 'not strict equal') 8 | 9 | t.ok(dist3.almostEqual(0, 0), 'zero diff') 10 | t.notOk(dist3.almostEqual(0, 1), 'over tolerance') 11 | t.ok(dist3.almostEqual(0, 1, 2), 'below tolerance') 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/scalar3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | almostEqual: require('./almostEqual.test'), 4 | create: require('./create.test'), 5 | equal: require('./equal.test'), 6 | transitFrom: require('./transitFrom.test'), 7 | transitTo: require('./transitTo.test'), 8 | validate: require('./validate.test') 9 | } 10 | 11 | module.exports = (t) => { 12 | Object.keys(units).forEach((unitName) => { 13 | t.test('affineplane.scalar3.' + unitName, units[unitName]) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/sphere3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const fine = require('../../index') // should be exported 2 | const sphere3 = fine.sphere3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: margin', (t) => { 6 | const p = { x: 0, y: 0, z: 0, r: 0 } 7 | const q = { x: 3, y: 3, z: 3, r: 3 } 8 | t.false(sphere3.almostEqual(p, q, 1)) 9 | t.false(sphere3.almostEqual(p, q, 11)) 10 | t.true(sphere3.almostEqual(p, q, 12)) 11 | t.true(sphere3.almostEqual(p, q, 13)) 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/sphere3/atCenter.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../index').sphere3 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic sphere center', (t) => { 5 | t.deepEqual( 6 | sphere3.atCenter({ x: 0, y: 0, z: 0, r: 0 }), 7 | { x: 0, y: 0, z: 0 }, 8 | 'trivial zero' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere3.atCenter({ x: 2, y: 2, z: 2, r: 2 }), 13 | { x: 2, y: 2, z: 2 }, 14 | 'should have correct props' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/sphere3/size.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../index').sphere3 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic sphere size', (t) => { 5 | t.deepEqual( 6 | sphere3.size({ x: 0, y: 0, z: 0, r: 0 }), 7 | { w: 0, h: 0, d: 0 }, 8 | 'trivial null sphere' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere3.size({ x: 2, y: 2, z: 2, r: 2 }), 13 | { w: 4, h: 4, d: 4 }, 14 | 'should have size double the radius' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lib/scalar1/create.js: -------------------------------------------------------------------------------- 1 | module.exports = (d) => { 2 | // @affineplane.scalar1.create(d) 3 | // 4 | // Create a valid scalar. Basically it is just the number itself. 5 | // 6 | // Parameters 7 | // d 8 | // a number 9 | // 10 | // Return 11 | // a number, the scalar. 12 | // 13 | // Throws 14 | // if the argument is not a number or is NaN 15 | // 16 | if (typeof d !== 'number' || isNaN(d)) { 17 | throw new Error('Invalid scalar value: ' + d) 18 | } 19 | 20 | return d 21 | } 22 | -------------------------------------------------------------------------------- /lib/size3/scaleBy.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz, multiplier) => { 2 | // @affineplane.size3.scaleBy(sz, multiplier) 3 | // 4 | // Scale and preserve aspect ratio. Multiplies all dimensions uniformly. 5 | // 6 | // Parameters: 7 | // sz 8 | // a size3 9 | // multiplier 10 | // a number 11 | // 12 | // Return: 13 | // a size3 14 | // 15 | return { 16 | w: Math.abs(sz.w * multiplier), 17 | h: Math.abs(sz.h * multiplier), 18 | d: Math.abs(sz.d * multiplier) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/vec2/validate.js: -------------------------------------------------------------------------------- 1 | module.exports = (v) => { 2 | // @affineplane.vec2.validate(v) 3 | // 4 | // Check if object is a valid vec2. 5 | // 6 | // Parameter 7 | // v 8 | // an object 9 | // 10 | // Return 11 | // a boolean 12 | // 13 | if (!v) { 14 | return false 15 | } 16 | 17 | if (typeof v.x !== 'number' || Number.isNaN(v.x)) { 18 | return false 19 | } 20 | if (typeof v.y !== 'number' || Number.isNaN(v.y)) { 21 | return false 22 | } 23 | 24 | return true 25 | } 26 | -------------------------------------------------------------------------------- /test/line3/create.test.js: -------------------------------------------------------------------------------- 1 | const line3 = require('../../lib/line3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: create valid line3', (t) => { 5 | const origin = { x: 2, y: 1, z: 1 } 6 | const span = { x: 3, y: 3, z: 0 } 7 | 8 | t.deepEqual( 9 | line3.create(origin, span), 10 | { origin, span }, 11 | 'correct format' 12 | ) 13 | 14 | t.ok( 15 | line3.validate(line3.create(origin, span)), 16 | 'ensure valid' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /test/path3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | combine: require('./combine.test'), 4 | create: require('./create.test'), 5 | projectToPlane: require('./projectToPlane.test'), 6 | transitFrom: require('./transitFrom.test'), 7 | transitTo: require('./transitTo.test'), 8 | validate: require('./validate.test') 9 | } 10 | 11 | module.exports = (t) => { 12 | Object.keys(units).forEach((unitName) => { 13 | t.test('affineplane.path3.' + unitName, units[unitName]) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/ray3/at.test.js: -------------------------------------------------------------------------------- 1 | const ray3 = require('../../lib/ray3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic ray at', (t) => { 5 | const ray = { x: 1, y: 1, z: 1, dx: 1, dy: 1, dz: -1 } 6 | 7 | t.deepEqual( 8 | ray3.at(ray, 3), 9 | { x: 4, y: 4, z: -2 }, 10 | 'three spans away from origin' 11 | ) 12 | 13 | t.deepEqual( 14 | ray3.at(ray, -3), 15 | { x: 1, y: 1, z: 1 }, 16 | 'negative position at origin' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /lib/dist2/transitFrom.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist2.transitFrom(dist, source) 2 | // 3 | // Transit a distance from the source basis 4 | // to the reference basis. 5 | // 6 | // Parameters: 7 | // dist 8 | // a number, a dist2 distance measure in the source basis. 9 | // source 10 | // a plane2, the source plane, represented 11 | // .. in the reference basis. 12 | // 13 | // Return: 14 | // a number, a dist2, represented on the reference basis. 15 | // 16 | module.exports = require('../scalar1/transitFrom') 17 | -------------------------------------------------------------------------------- /lib/dist3/transitTo.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist3.transitTo(dist, target) 2 | // 3 | // Transit a dist3 to a target basis. 4 | // In other words, represent the distance 5 | // in the coordinate system of the basis. 6 | // 7 | // Parameters: 8 | // dist 9 | // a dist3 in the reference basis. 10 | // target 11 | // a plane3, the target basis, represented 12 | // .. in the reference basis. 13 | // 14 | // Return: 15 | // a dist3 in the target basis. 16 | // 17 | module.exports = require('../scalar1/transitTo') 18 | -------------------------------------------------------------------------------- /lib/size3/atNorm.js: -------------------------------------------------------------------------------- 1 | module.exports = (sz, nw, nh, nd) => { 2 | // @affineplane.size3.atNorm(sz, nw, nh, nd) 3 | // 4 | // Find a point in the volume. 5 | // 6 | // Parameters 7 | // sz 8 | // a size3 9 | // nw 10 | // a normalized width in 0..1 11 | // nh 12 | // a normalized height 13 | // nd 14 | // a normalized depth 15 | // 16 | // Return 17 | // a point3 18 | // 19 | return { 20 | x: sz.w * nw, 21 | y: sz.h * nh, 22 | z: sz.d * nd 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/vec2/scaleBy.js: -------------------------------------------------------------------------------- 1 | module.exports = (vec, multiplier) => { 2 | // @affineplane.vec2.scaleBy(vec, multiplier) 3 | // 4 | // The scalar multiplication of a vector. 5 | // Scale the vector by a multiplier. 6 | // The direction of the vector does not change. 7 | // 8 | // Parameters: 9 | // vec 10 | // a vec2 11 | // multiplier 12 | // a number 13 | // 14 | // Return 15 | // a vec2 16 | // 17 | return { 18 | x: vec.x * multiplier, 19 | y: vec.y * multiplier 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/vec4/index.js: -------------------------------------------------------------------------------- 1 | // @affineplane.vec4 2 | // 3 | // A vec4 is a 4D vector { x, y, z, w }. 4 | // 5 | 6 | // @affineplane.vec4.ZERO 7 | // 8 | // The zero vector in 4D 9 | // 10 | exports.ZERO = { x: 0, y: 0, z: 0, w: 0 } 11 | 12 | exports.add = require('./add') 13 | exports.almostEqual = require('./almostEqual') 14 | exports.create = require('./create') 15 | exports.equal = require('./equal') 16 | exports.norm = require('./norm') 17 | exports.scaleBy = require('./scaleBy') 18 | exports.validate = require('./validate') 19 | -------------------------------------------------------------------------------- /test/plane2/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../lib/plane2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: smoke almostEqual', (t) => { 5 | const a = { a: 1, b: 2, x: 3, y: 4 } 6 | const b = { a: 1, b: 2, x: 3, y: 4 } 7 | const c = { a: 1, b: 0, x: 0, y: 0 } 8 | 9 | t.true(plane2.almostEqual(a, a), 'same object') 10 | t.true(plane2.almostEqual(a, b), 'element-wise equal') 11 | t.false(plane2.almostEqual(a, c), 'values differ greatly') 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/size3/scaleBy.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size3 = affineplane.size3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic', (t) => { 6 | const s = { w: 1, h: 2, d: 3 } 7 | t.deepEqual( 8 | size3.scaleBy(s, -1), 9 | { w: 1, h: 2, d: 3 }, 10 | 'should stay absolute' 11 | ) 12 | 13 | t.deepEqual( 14 | size3.scaleBy(s, 2), 15 | { w: 2, h: 4, d: 6 }, 16 | 'should scale uniformly' 17 | ) 18 | 19 | t.end() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /test/sphere2/offset.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic offset', (t) => { 5 | t.deepEqual( 6 | sphere2.offset({ x: 0, y: 0, r: 1 }, 1, 1), 7 | { x: 1, y: 1, r: 1 }, 8 | 'should move by unit' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere2.offset({ x: 3, y: -3, r: 1 }, 1, 1), 13 | { x: 4, y: -2, r: 1 }, 14 | 'non zero center point should move by unit' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/vec2/unit.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic unit vector', (t) => { 6 | t.almostEqual( 7 | vec2.unit({ x: 0, y: 0 }), 8 | { x: 1, y: 0 }, 9 | 'zero vector towards x' 10 | ) 11 | 12 | t.almostEqual( 13 | vec2.normalize({ x: 3, y: 4 }), // orig.len. 5 14 | { x: 3 / 5, y: 4 / 5 }, 15 | 'direction does not change' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/vec3/fromSpherical.test.js: -------------------------------------------------------------------------------- 1 | const vec3 = require('../../lib/vec3') 2 | const PI = Math.PI 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic polar coords', (t) => { 6 | t.almostEqual( 7 | vec3.fromSpherical(2, PI / 2, PI / 2), 8 | { x: 0, y: 0, z: 2 } 9 | ) 10 | 11 | t.end() 12 | }) 13 | 14 | ts.test('case: unset pitch', (t) => { 15 | t.almostEqual( 16 | vec3.fromSpherical(2, PI / 2), 17 | { x: 0, y: 2, z: 0 } 18 | ) 19 | 20 | t.end() 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /lib/box2/getPath.js: -------------------------------------------------------------------------------- 1 | const at = require('./at') 2 | 3 | module.exports = (box) => { 4 | // @affineplane.box2.getPath(box) 5 | // @affineplane.box2.getPoints 6 | // @affineplane.box2.getPolygon 7 | // 8 | // Get the box corner points as a path. Points are in clock-wise order. 9 | // 10 | // Parameters: 11 | // box 12 | // 13 | // Return 14 | // a path2 15 | // 16 | return [ 17 | at(box, 0, 0), 18 | at(box, box.w, 0), 19 | at(box, box.w, box.h), 20 | at(box, 0, box.h) 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /lib/scalar2/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar2.almostEqual(c, d[, tolerance]) 2 | // 3 | // Test if the second order scalars c, d are almost equal within 4 | // the margin of tolerance. 5 | // 6 | // Parameters 7 | // c 8 | // a number, a scalar2 9 | // d 10 | // a number, a scalar2 11 | // tolerance 12 | // optional number, default is affineplane.epsilon. 13 | // .. Set to 0 for strict comparison. 14 | // 15 | // Return 16 | // a boolean 17 | // 18 | module.exports = require('../scalar1/almostEqual') 19 | -------------------------------------------------------------------------------- /lib/scalar3/almostEqual.js: -------------------------------------------------------------------------------- 1 | // @affineplane.scalar3.almostEqual(c, d[, tolerance]) 2 | // 3 | // Test if the third-order scalars c, d are almost equal within 4 | // the margin of tolerance. 5 | // 6 | // Parameters 7 | // c 8 | // a number, a scalar3 9 | // d 10 | // a number, a scalar3 11 | // tolerance 12 | // optional number, default is affineplane.epsilon. 13 | // .. Set to 0 for strict comparison. 14 | // 15 | // Return 16 | // a boolean 17 | // 18 | module.exports = require('../scalar1/almostEqual') 19 | -------------------------------------------------------------------------------- /lib/sphere3/translate.js: -------------------------------------------------------------------------------- 1 | module.exports = (c, vec) => { 2 | // @affineplane.sphere3.translate(c, vec) 3 | // 4 | // Translate the sphere by the vector. Does not affect radius. 5 | // See affineplane.sphere3.offset to translate by scalars. 6 | // 7 | // Parameters: 8 | // c 9 | // a sphere3 10 | // vec 11 | // a vec3 12 | // 13 | // Return 14 | // a sphere3 15 | // 16 | return { 17 | x: c.x + vec.x, 18 | y: c.y + vec.y, 19 | z: c.z + vec.z, 20 | r: c.r 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/dist3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | almostEqual: require('./almostEqual.test'), 4 | create: require('./create.test'), 5 | projectToPlane: require('./projectToPlane.test'), 6 | transitFrom: require('./transitFrom.test'), 7 | transitTo: require('./transitTo.test'), 8 | validate: require('./validate.test') 9 | } 10 | 11 | module.exports = (t) => { 12 | Object.keys(units).forEach((unitName) => { 13 | t.test('affineplane.dist3.' + unitName, units[unitName]) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/plane3/copy.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic copy', (t) => { 5 | t.deepEqual( 6 | plane3.copy({ a: 1, b: 2, x: 3, y: 4, z: 5 }), 7 | { a: 1, b: 2, x: 3, y: 4, z: 5 }, 8 | 'should have same content' 9 | ) 10 | 11 | const p = { a: 1, b: 2, x: 3, y: 4, z: 5 } 12 | t.notEqual( 13 | plane3.clone(p), 14 | p, 15 | 'should not be the same object' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/size3/atNorm.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const size3 = affineplane.size3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic atNorm', (t) => { 6 | const sz = size3.create(1, 2, 3) 7 | 8 | t.deepEqual( 9 | size3.atNorm(sz, 0, 0, 0), 10 | { x: 0, y: 0, z: 0 }, 11 | 'corner zero' 12 | ) 13 | 14 | t.deepEqual( 15 | size3.atNorm(sz, 1, 1, 1), 16 | { x: 1, y: 2, z: 3 }, 17 | 'corner one' 18 | ) 19 | 20 | t.end() 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /test/vec2/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec2 = affineplane.vec2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: zeroes and ones', (t) => { 6 | t.ok( 7 | vec2.equal( 8 | { x: 0, y: 0 }, 9 | { x: 0, y: 0 } 10 | ), 11 | 'zero vectors equal' 12 | ) 13 | 14 | t.notOk( 15 | vec2.equal( 16 | { x: 1, y: 1 }, 17 | { x: 2, y: 1 } 18 | ), 19 | 'vectors different' 20 | ) 21 | 22 | t.end() 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /lib/helm2/setTranslation.js: -------------------------------------------------------------------------------- 1 | module.exports = (tr, vec) => { 2 | // @affineplane.helm2.setTranslation(tr, vec) 3 | // 4 | // Replace translation property of the transformation. 5 | // The dilation and rotation properties are preserved. 6 | // 7 | // Parameters: 8 | // tr 9 | // a helm2 10 | // vec 11 | // a vec2, the new translation vector 12 | // 13 | // Return: 14 | // a helm2 15 | // 16 | return { 17 | a: tr.a, 18 | b: tr.b, 19 | x: vec.x, 20 | y: vec.y 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/vec2/rotateBy.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, radians) => { 2 | // @affineplane.vec2.rotateBy(v, radians) 3 | // 4 | // Rotate vector by the given angle. 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // radians 10 | // a number, from positive x-axis towards positive y-axis 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | const co = Math.cos(radians) 16 | const si = Math.sin(radians) 17 | 18 | return { 19 | x: v.x * co - v.y * si, 20 | y: v.x * si + v.y * co 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/dir3/toVector.test.js: -------------------------------------------------------------------------------- 1 | const dir3 = require('../../lib/dir3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic dir from vector', (t) => { 5 | t.almostEqual( 6 | dir3.toVector({ x: 0, y: 0, z: 1 }), 7 | { x: 0, y: 0, z: 1 }, 8 | 'default magnitude' 9 | ) 10 | 11 | const h2 = Math.sqrt(2) / 2 12 | t.almostEqual( 13 | dir3.toVector({ x: h2, y: h2, z: 0 }, 4), 14 | { x: 4 * h2, y: 4 * h2, z: 0 }, 15 | 'with magnitude' 16 | ) 17 | 18 | t.end() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /lib/plane2/translateTo.js: -------------------------------------------------------------------------------- 1 | module.exports = function (plane, p) { 2 | // @affineplane.plane2.translateTo(plane, p) 3 | // 4 | // Move the plane origin to a new point. 5 | // This translates the plane to a new position. 6 | // 7 | // Parameters 8 | // plane 9 | // a plane2 on the reference plane 10 | // p 11 | // a point2 on the reference plane 12 | // 13 | // Return 14 | // a plane2 15 | // 16 | return { 17 | a: plane.a, 18 | b: plane.b, 19 | x: p.x, 20 | y: p.y 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/path2/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path2 = affineplane.path2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transitTo', (t) => { 6 | // let path, plane 7 | 8 | const path = [{ x: 0, y: 2 }, { x: 2, y: 4 }] 9 | const plane = { a: 2, b: 0, x: 0, y: 2 } 10 | 11 | t.deepEqual( 12 | path2.transitTo(path, plane), 13 | [{ x: 0, y: 0 }, { x: 1, y: 1 }], 14 | 'scale and translation should affect' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/plane2/limitScale.test.js: -------------------------------------------------------------------------------- 1 | const plane2 = require('../../index').plane2 2 | const limitScale = plane2.limitScale 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke limitDilation', (t) => { 6 | // More comprehensive test in helm2, because same code under the hood. 7 | 8 | const rothalf = { a: 0, b: 0.5, x: 2, y: 2 } 9 | t.deepEqual( 10 | limitScale(rothalf, 0.64, 0.75), 11 | { a: 0, b: 0.64, x: 2, y: 2 }, 12 | 'below limit, scale to minimum' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/rect2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | at: require('./at.test'), 4 | atNorm: require('./atNorm.test'), 5 | create: require('./create.test'), 6 | getArea: require('./getArea.test'), 7 | getBounds: require('./getBounds.test'), 8 | transitFrom: require('./transitFrom.test'), 9 | transitTo: require('./transitTo.test') 10 | } 11 | 12 | module.exports = (t) => { 13 | Object.keys(units).forEach((unitName) => { 14 | t.test('affineplane.rect2.' + unitName, units[unitName]) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/rect3/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | at: require('./at.test'), 4 | atNorm: require('./atNorm.test'), 5 | create: require('./create.test'), 6 | getArea: require('./getArea.test'), 7 | getBounds: require('./getBounds.test'), 8 | transitFrom: require('./transitFrom.test'), 9 | transitTo: require('./transitTo.test') 10 | } 11 | 12 | module.exports = (t) => { 13 | Object.keys(units).forEach((unitName) => { 14 | t.test('affineplane.rect3.' + unitName, units[unitName]) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /lib/box2/translate.js: -------------------------------------------------------------------------------- 1 | module.exports = (box, vec) => { 2 | // @affineplane.box2.translate(box, vec) 3 | // 4 | // Move the box horizontally and vertically by a vector. 5 | // See affineplane.box2.offset to move by scalars. 6 | // 7 | // Parameters: 8 | // box 9 | // a box2 10 | // vec 11 | // a vec2 12 | // 13 | // Return 14 | // a box2 15 | // 16 | return { 17 | a: box.a, 18 | b: box.b, 19 | x: box.x + vec.x, 20 | y: box.y + vec.y, 21 | w: box.w, 22 | h: box.h 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/dist2/transitTo.js: -------------------------------------------------------------------------------- 1 | // @affineplane.dist2.transitTo(dist, target) 2 | // 3 | // Transit a dist2 to another basis. 4 | // In other words, represent the distance 5 | // in the coordinate system of the target. 6 | // 7 | // Parameters: 8 | // dist 9 | // a number, a dist2 in the reference basis. 10 | // target 11 | // a plane2, the target basis, represented 12 | // .. in the reference basis. 13 | // 14 | // Return: 15 | // a number, a dist2 in the target basis. 16 | // 17 | module.exports = require('../scalar1/transitTo') 18 | -------------------------------------------------------------------------------- /lib/line2/normal.js: -------------------------------------------------------------------------------- 1 | module.exports = (line) => { 2 | // @affineplane.line2.normal(line) 3 | // 4 | // Get a normal vector for the line. It is perpendicular to the line. 5 | // Note that a line has two normal vectors, one for each side. 6 | // The returned normal is the one at the right hand. 7 | // 8 | // Parameters: 9 | // line 10 | // a line2 11 | // 12 | // Return 13 | // a vec2, a vector perpendicular to the line. 14 | // 15 | return { 16 | x: -line.span.y, 17 | y: line.span.x 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/segment2/validate.js: -------------------------------------------------------------------------------- 1 | const validatePoint = require('../point2/validate') 2 | 3 | module.exports = (seg) => { 4 | // @affineplane.segment2.validate(seg) 5 | // 6 | // Check if the object is a valid segment2. 7 | // A valid segment2 is an array of two valid point2 objects. 8 | // 9 | // Parameter 10 | // seg 11 | // an object 12 | // 13 | // Return 14 | // a boolean, true if valid 15 | // 16 | return Array.isArray(seg) && seg.length === 2 && 17 | validatePoint(seg[0]) && validatePoint(seg[1]) 18 | } 19 | -------------------------------------------------------------------------------- /lib/segment3/validate.js: -------------------------------------------------------------------------------- 1 | const validatePoint = require('../point3/validate') 2 | 3 | module.exports = (seg) => { 4 | // @affineplane.segment3.validate(seg) 5 | // 6 | // Check if the object is a valid segment3. 7 | // A valid segment3 is an array of two valid point3 objects. 8 | // 9 | // Parameter 10 | // seg 11 | // an object 12 | // 13 | // Return 14 | // a boolean, true if valid 15 | // 16 | return Array.isArray(seg) && seg.length === 2 && 17 | validatePoint(seg[0]) && validatePoint(seg[1]) 18 | } 19 | -------------------------------------------------------------------------------- /test/path2/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const path2 = affineplane.path2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transitFrom', (t) => { 6 | // let path, plane 7 | 8 | const path = [{ x: 0, y: 0 }, { x: 1, y: 1 }] 9 | const plane = { a: 2, b: 0, x: 0, y: 2 } 10 | 11 | t.deepEqual( 12 | path2.transitFrom(path, plane), 13 | [{ x: 0, y: 2 }, { x: 2, y: 4 }], 14 | 'scale and translation should affect' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/plane3/almostEqual.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../lib/plane3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: smoke almostEqual', (t) => { 5 | const a = { a: 1, b: 2, x: 3, y: 4, z: 5 } 6 | const b = { a: 1, b: 2, x: 3, y: 4, z: 5 } 7 | const c = { a: 1, b: 0, x: 0, y: 0, z: 0 } 8 | 9 | t.true(plane3.almostEqual(a, a), 'same object') 10 | t.true(plane3.almostEqual(a, b), 'element-wise equal') 11 | t.false(plane3.almostEqual(a, c), 'values differ greatly') 12 | 13 | t.end() 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/segment2/transitTo.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const segment2 = affineplane.segment2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transitTo', (t) => { 6 | // let seg, plane 7 | 8 | const seg = [{ x: 0, y: 2 }, { x: 2, y: 4 }] 9 | const plane = { a: 2, b: 0, x: 0, y: 2 } 10 | 11 | t.deepEqual( 12 | segment2.transitTo(seg, plane), 13 | [{ x: 0, y: 0 }, { x: 1, y: 1 }], 14 | 'scale and translation should affect' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /lib/helm2/solveLeft.js: -------------------------------------------------------------------------------- 1 | const invert = require('./invert') 2 | const compose = require('./compose') 3 | 4 | module.exports = (tb, tc) => { 5 | // @affineplane.helm2.solveLeft(tb, tc) 6 | // 7 | // Given transforms B, C, find transform A, where AB = C. 8 | // Given that B is invertible, then A = C * iB. 9 | // 10 | // Parameters: 11 | // tb 12 | // a helm2 13 | // tc 14 | // a helm2 15 | // 16 | // Return 17 | // a helm2, a transform 18 | // 19 | const inv = invert(tb) 20 | return compose(tc, inv) 21 | } 22 | -------------------------------------------------------------------------------- /lib/helm3/setTranslation.js: -------------------------------------------------------------------------------- 1 | module.exports = (tr, vec) => { 2 | // @affineplane.helm3.setTranslation(tr, vec) 3 | // 4 | // Replace translation property of the transformation. 5 | // The dilation and rotation properties are preserved. 6 | // 7 | // Parameters: 8 | // tr 9 | // a helm3 10 | // vec 11 | // a vec3, the new translation vector 12 | // 13 | // Return: 14 | // a helm3 15 | // 16 | return { 17 | a: tr.a, 18 | b: tr.b, 19 | x: vec.x, 20 | y: vec.y, 21 | z: vec.z 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/vec2/rotateTo.js: -------------------------------------------------------------------------------- 1 | module.exports = (v, radians) => { 2 | // @affineplane.vec2.rotateTo(v, radians) 3 | // 4 | // Rotate vector so that it points to the given angle. 5 | // 6 | // Parameters 7 | // v 8 | // a vec2 9 | // radians 10 | // a number from positive x-axis towards positive y-axis 11 | // 12 | // Return 13 | // a vec2 14 | // 15 | const magnitude = Math.sqrt(v.x * v.x + v.y * v.y) 16 | return { 17 | x: magnitude * Math.cos(radians), 18 | y: magnitude * Math.sin(radians) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/scalar1/create.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const scalar1 = affineplane.scalar1 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic create', (t) => { 6 | t.equal(scalar1.create(-3), -3, 'should allow negative value') 7 | t.equal(scalar1.create(0), 0, 'should allow zero') 8 | 9 | t.throws(() => { 10 | scalar1.create(NaN) 11 | }, 'should detect NaN') 12 | 13 | t.throws(() => { 14 | scalar1.create('0') 15 | }, 'should detect string') 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/sphere2/polarOffset.test.js: -------------------------------------------------------------------------------- 1 | const sphere2 = require('../../lib/sphere2') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic polar offset', (t) => { 5 | t.deepEqual( 6 | sphere2.polarOffset({ x: 0, y: 0, r: 1 }, 1, 0), 7 | { x: 1, y: 0, r: 1 }, 8 | 'should move towards x' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere2.polarOffset({ x: 3, y: -3, r: 2 }, 2, Math.PI / 2), 13 | { x: 3, y: -1, r: 2 }, 14 | 'should move towards y, keep radius' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/sphere3/volume.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../lib/sphere3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: sphere volume', (t) => { 5 | let ball 6 | 7 | ball = { x: 0, y: 1, z: 0, r: 0 } 8 | t.equal(sphere3.volume(ball), 0, 'empty sphere') 9 | 10 | ball = { x: 0, y: 1, z: 0, r: 1 } 11 | t.equal(sphere3.volume(ball), 4 * Math.PI / 3, 'unit sphere') 12 | 13 | ball = { x: 0, y: 1, z: 0, r: 2 } 14 | t.equal(sphere3.volume(ball), 32 * Math.PI / 3, 'two sphere') 15 | 16 | t.end() 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /lib/circle3/offset.js: -------------------------------------------------------------------------------- 1 | // @affineplane.circle3.offset(c, dx, dy[, dz]) 2 | // 3 | // Offset a circle by scalars dx, dy, dz. 4 | // See affineplane.circle3.translate to offset by a vector. 5 | // 6 | // Parameters: 7 | // c 8 | // a circle3 9 | // dx 10 | // a number, an offset along x-axis. 11 | // dy 12 | // a number, an offset along y-axis. 13 | // dz 14 | // optional number. The offset along z-axis, default is 0. 15 | // 16 | // Return 17 | // a circle3, translated 18 | // 19 | module.exports = require('../sphere3/offset') 20 | -------------------------------------------------------------------------------- /test/plane3/limitScale.test.js: -------------------------------------------------------------------------------- 1 | const plane3 = require('../../index').plane3 2 | const limitScale = plane3.limitScale 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: smoke limitDilation', (t) => { 6 | // More comprehensive test in helm3, because the same code under the hood. 7 | 8 | const rothalf = { a: 0, b: 0.5, x: 1, y: 2, z: 3 } 9 | t.deepEqual( 10 | limitScale(rothalf, 0.64, 0.75), 11 | { a: 0, b: 0.64, x: 1, y: 2, z: 3 }, 12 | 'below limit, scale to minimum' 13 | ) 14 | 15 | t.end() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /test/segment2/transitFrom.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const segment2 = affineplane.segment2 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: basic transitFrom', (t) => { 6 | // let seg, plane 7 | 8 | const seg = [{ x: 0, y: 0 }, { x: 1, y: 1 }] 9 | const basis = { a: 2, b: 0, x: 0, y: 2 } 10 | 11 | t.deepEqual( 12 | segment2.transitFrom(seg, basis), 13 | [{ x: 0, y: 2 }, { x: 2, y: 4 }], 14 | 'scale and translation should affect' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/size2/index.test.js: -------------------------------------------------------------------------------- 1 | // A unit for each method. 2 | const units = { 3 | almostEqual: require('./almostEqual.test'), 4 | create: require('./create.test'), 5 | equal: require('./equal.test'), 6 | scaleBy: require('./scaleBy.test'), 7 | transitFrom: require('./transitFrom.test'), 8 | transitTo: require('./transitTo.test'), 9 | validate: require('./validate.test') 10 | } 11 | 12 | module.exports = (t) => { 13 | Object.keys(units).forEach((unitName) => { 14 | t.test('affineplane.size2.' + unitName, units[unitName]) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /test/sphere3/offset.test.js: -------------------------------------------------------------------------------- 1 | const sphere3 = require('../../lib/sphere3') 2 | 3 | module.exports = (ts) => { 4 | ts.test('case: basic offset', (t) => { 5 | t.deepEqual( 6 | sphere3.offset({ x: 0, y: 0, z: 0, r: 1 }, 1, 1, 1), 7 | { x: 1, y: 1, z: 1, r: 1 }, 8 | 'should move by unit' 9 | ) 10 | 11 | t.deepEqual( 12 | sphere3.offset({ x: 3, y: -3, z: 3, r: 1 }, 1, 1, 1), 13 | { x: 4, y: -2, z: 4, r: 1 }, 14 | 'non zero center point should move by unit' 15 | ) 16 | 17 | t.end() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /test/vec3/equal.test.js: -------------------------------------------------------------------------------- 1 | const affineplane = require('../../index') 2 | const vec3 = affineplane.vec3 3 | 4 | module.exports = (ts) => { 5 | ts.test('case: zeroes and ones', (t) => { 6 | t.ok( 7 | vec3.equal( 8 | { x: 0, y: 0, z: 0 }, 9 | { x: 0, y: 0, z: 0 } 10 | ), 11 | 'zero vectors equal' 12 | ) 13 | 14 | t.notOk( 15 | vec3.equal( 16 | { x: 1, y: 1, z: 1 }, 17 | { x: 1, y: 1, z: 2 } 18 | ), 19 | 'vectors different' 20 | ) 21 | 22 | t.end() 23 | }) 24 | } 25 | --------------------------------------------------------------------------------