This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.
mightyscape-1.1-deprecated/extensions/fablabchemnitz/papercraft/openjscad/node_modules/@jscad/csg/src/math/OrthoNormalBasis.js

203 lines
7.0 KiB
JavaScript

const Vector2D = require('./Vector2')
const Vector3D = require('./Vector3')
const Line2D = require('./Line2')
const Line3D = require('./Line3')
const Plane = require('./Plane')
// # class OrthoNormalBasis
// Reprojects points on a 3D plane onto a 2D plane
// or from a 2D plane back onto the 3D plane
const OrthoNormalBasis = function (plane, rightvector) {
if (arguments.length < 2) {
// choose an arbitrary right hand vector, making sure it is somewhat orthogonal to the plane normal:
rightvector = plane.normal.randomNonParallelVector()
} else {
rightvector = new Vector3D(rightvector)
}
this.v = plane.normal.cross(rightvector).unit()
this.u = this.v.cross(plane.normal)
this.plane = plane
this.planeorigin = plane.normal.times(plane.w)
}
// Get an orthonormal basis for the standard XYZ planes.
// Parameters: the names of two 3D axes. The 2d x axis will map to the first given 3D axis, the 2d y
// axis will map to the second.
// Prepend the axis with a "-" to invert the direction of this axis.
// For example: OrthoNormalBasis.GetCartesian("-Y","Z")
// will return an orthonormal basis where the 2d X axis maps to the 3D inverted Y axis, and
// the 2d Y axis maps to the 3D Z axis.
OrthoNormalBasis.GetCartesian = function (xaxisid, yaxisid) {
let axisid = xaxisid + '/' + yaxisid
let planenormal, rightvector
if (axisid === 'X/Y') {
planenormal = [0, 0, 1]
rightvector = [1, 0, 0]
} else if (axisid === 'Y/-X') {
planenormal = [0, 0, 1]
rightvector = [0, 1, 0]
} else if (axisid === '-X/-Y') {
planenormal = [0, 0, 1]
rightvector = [-1, 0, 0]
} else if (axisid === '-Y/X') {
planenormal = [0, 0, 1]
rightvector = [0, -1, 0]
} else if (axisid === '-X/Y') {
planenormal = [0, 0, -1]
rightvector = [-1, 0, 0]
} else if (axisid === '-Y/-X') {
planenormal = [0, 0, -1]
rightvector = [0, -1, 0]
} else if (axisid === 'X/-Y') {
planenormal = [0, 0, -1]
rightvector = [1, 0, 0]
} else if (axisid === 'Y/X') {
planenormal = [0, 0, -1]
rightvector = [0, 1, 0]
} else if (axisid === 'X/Z') {
planenormal = [0, -1, 0]
rightvector = [1, 0, 0]
} else if (axisid === 'Z/-X') {
planenormal = [0, -1, 0]
rightvector = [0, 0, 1]
} else if (axisid === '-X/-Z') {
planenormal = [0, -1, 0]
rightvector = [-1, 0, 0]
} else if (axisid === '-Z/X') {
planenormal = [0, -1, 0]
rightvector = [0, 0, -1]
} else if (axisid === '-X/Z') {
planenormal = [0, 1, 0]
rightvector = [-1, 0, 0]
} else if (axisid === '-Z/-X') {
planenormal = [0, 1, 0]
rightvector = [0, 0, -1]
} else if (axisid === 'X/-Z') {
planenormal = [0, 1, 0]
rightvector = [1, 0, 0]
} else if (axisid === 'Z/X') {
planenormal = [0, 1, 0]
rightvector = [0, 0, 1]
} else if (axisid === 'Y/Z') {
planenormal = [1, 0, 0]
rightvector = [0, 1, 0]
} else if (axisid === 'Z/-Y') {
planenormal = [1, 0, 0]
rightvector = [0, 0, 1]
} else if (axisid === '-Y/-Z') {
planenormal = [1, 0, 0]
rightvector = [0, -1, 0]
} else if (axisid === '-Z/Y') {
planenormal = [1, 0, 0]
rightvector = [0, 0, -1]
} else if (axisid === '-Y/Z') {
planenormal = [-1, 0, 0]
rightvector = [0, -1, 0]
} else if (axisid === '-Z/-Y') {
planenormal = [-1, 0, 0]
rightvector = [0, 0, -1]
} else if (axisid === 'Y/-Z') {
planenormal = [-1, 0, 0]
rightvector = [0, 1, 0]
} else if (axisid === 'Z/Y') {
planenormal = [-1, 0, 0]
rightvector = [0, 0, 1]
} else {
throw new Error('OrthoNormalBasis.GetCartesian: invalid combination of axis identifiers. Should pass two string arguments from [X,Y,Z,-X,-Y,-Z], being two different axes.')
}
return new OrthoNormalBasis(new Plane(new Vector3D(planenormal), 0), new Vector3D(rightvector))
}
/*
// test code for OrthoNormalBasis.GetCartesian()
OrthoNormalBasis.GetCartesian_Test=function() {
let axisnames=["X","Y","Z","-X","-Y","-Z"];
let axisvectors=[[1,0,0], [0,1,0], [0,0,1], [-1,0,0], [0,-1,0], [0,0,-1]];
for(let axis1=0; axis1 < 3; axis1++) {
for(let axis1inverted=0; axis1inverted < 2; axis1inverted++) {
let axis1name=axisnames[axis1+3*axis1inverted];
let axis1vector=axisvectors[axis1+3*axis1inverted];
for(let axis2=0; axis2 < 3; axis2++) {
if(axis2 != axis1) {
for(let axis2inverted=0; axis2inverted < 2; axis2inverted++) {
let axis2name=axisnames[axis2+3*axis2inverted];
let axis2vector=axisvectors[axis2+3*axis2inverted];
let orthobasis=OrthoNormalBasis.GetCartesian(axis1name, axis2name);
let test1=orthobasis.to3D(new Vector2D([1,0]));
let test2=orthobasis.to3D(new Vector2D([0,1]));
let expected1=new Vector3D(axis1vector);
let expected2=new Vector3D(axis2vector);
let d1=test1.distanceTo(expected1);
let d2=test2.distanceTo(expected2);
if( (d1 > 0.01) || (d2 > 0.01) ) {
throw new Error("Wrong!");
}}}}}}
throw new Error("OK");
};
*/
// The z=0 plane, with the 3D x and y vectors mapped to the 2D x and y vector
OrthoNormalBasis.Z0Plane = function () {
let plane = new Plane(new Vector3D([0, 0, 1]), 0)
return new OrthoNormalBasis(plane, new Vector3D([1, 0, 0]))
}
OrthoNormalBasis.prototype = {
getProjectionMatrix: function () {
const Matrix4x4 = require('./Matrix4') // FIXME: circular dependencies Matrix=>OrthoNormalBasis => Matrix
return new Matrix4x4([
this.u.x, this.v.x, this.plane.normal.x, 0,
this.u.y, this.v.y, this.plane.normal.y, 0,
this.u.z, this.v.z, this.plane.normal.z, 0,
0, 0, -this.plane.w, 1
])
},
getInverseProjectionMatrix: function () {
const Matrix4x4 = require('./Matrix4') // FIXME: circular dependencies Matrix=>OrthoNormalBasis => Matrix
let p = this.plane.normal.times(this.plane.w)
return new Matrix4x4([
this.u.x, this.u.y, this.u.z, 0,
this.v.x, this.v.y, this.v.z, 0,
this.plane.normal.x, this.plane.normal.y, this.plane.normal.z, 0,
p.x, p.y, p.z, 1
])
},
to2D: function (vec3) {
return new Vector2D(vec3.dot(this.u), vec3.dot(this.v))
},
to3D: function (vec2) {
return this.planeorigin.plus(this.u.times(vec2.x)).plus(this.v.times(vec2.y))
},
line3Dto2D: function (line3d) {
let a = line3d.point
let b = line3d.direction.plus(a)
let a2d = this.to2D(a)
let b2d = this.to2D(b)
return Line2D.fromPoints(a2d, b2d)
},
line2Dto3D: function (line2d) {
let a = line2d.origin()
let b = line2d.direction().plus(a)
let a3d = this.to3D(a)
let b3d = this.to3D(b)
return Line3D.fromPoints(a3d, b3d)
},
transform: function (matrix4x4) {
// todo: this may not work properly in case of mirroring
let newplane = this.plane.transform(matrix4x4)
let rightpointTransformed = this.u.transform(matrix4x4)
let originTransformed = new Vector3D(0, 0, 0).transform(matrix4x4)
let newrighthandvector = rightpointTransformed.minus(originTransformed)
let newbasis = new OrthoNormalBasis(newplane, newrighthandvector)
return newbasis
}
}
module.exports = OrthoNormalBasis