3dmol
Version:
JavaScript/TypeScript molecular visualization library
1,536 lines (1,292 loc) • 61.4 kB
HTML
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="Author" content="David Koes & 3Dmoljs Contributors"><meta name="Description" content="A modern, object-oriented JavaScript library for visualizing molecular data"><title>Source: WebGL/math/math.ts</title><!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><style>article ul li{list-style:disc}</style><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">3Dmol.js</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="mei5HJjYKLn6aua5Z5PM5"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="$3Dmol.Label.html">Label</a></div><div class="sidebar-section-children"><a href="$3Dmol.StateManager.html">StateManager</a></div><div class="sidebar-section-children"><a href="$3Dmol.UI.html">UI</a></div><div class="sidebar-section-children"><a href="Color.html">Color</a></div><div class="sidebar-section-children"><a href="CustomLinear.html">CustomLinear</a></div><div class="sidebar-section-children"><a href="Cylinder.html">Cylinder</a></div><div class="sidebar-section-children"><a href="GLModel.html">GLModel</a></div><div class="sidebar-section-children"><a href="GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLShape_GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLViewer.html">GLViewer</a></div><div class="sidebar-section-children"><a href="GLVolumetricRender.html">GLVolumetricRender</a></div><div class="sidebar-section-children"><a href="Matrix3.html">Matrix3</a></div><div class="sidebar-section-children"><a href="Matrix4.html">Matrix4</a></div><div class="sidebar-section-children"><a href="Quaternion.html">Quaternion</a></div><div class="sidebar-section-children"><a href="ROYGB.html">ROYGB</a></div><div class="sidebar-section-children"><a href="RWB.html">RWB</a></div><div class="sidebar-section-children"><a href="Ray.html">Ray</a></div><div class="sidebar-section-children"><a href="Sinebow.html">Sinebow</a></div><div class="sidebar-section-children"><a href="Sphere.html">Sphere</a></div><div class="sidebar-section-children"><a href="Surface.html">Surface</a></div><div class="sidebar-section-children"><a href="Triangle.html">Triangle</a></div><div class="sidebar-section-children"><a href="Vector2.html">Vector2</a></div><div class="sidebar-section-children"><a href="Vector3.html">Vector3</a></div><div class="sidebar-section-children"><a href="VolumeData.html">VolumeData</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="kv4Yx5z0THf_b8XR4Gje1"><div>Namespaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="GLDraw.html">GLDraw</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="ykThSufQWJcKGT1kXzr-A"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-code.html">Using 3Dmol within your code</a></div><div class="sidebar-section-children"><a href="tutorial-embeddable.html">Embedding a 3Dmol Viewer</a></div><div class="sidebar-section-children"><a href="tutorial-home.html">3Dmol Tutorials - Home</a></div><div class="sidebar-section-children"><a href="tutorial-learning_environment.html">Active Learning with 3Dmol.js</a></div><div class="sidebar-section-children"><a href="tutorial-url.html">Viewing Molecules with the 3Dmol Server</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="XcP4RUEg6tp7YKHbBVi9E"><div>Interfaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="AmbientOcclusionStyle.html">AmbientOcclusionStyle</a></div><div class="sidebar-section-children"><a href="ArrowSpec.html">ArrowSpec</a></div><div class="sidebar-section-children"><a href="AtomSelectionSpec.html">AtomSelectionSpec</a></div><div class="sidebar-section-children"><a href="AtomSpec.html">AtomSpec</a></div><div class="sidebar-section-children"><a href="AtomStyleSpec.html">AtomStyleSpec</a></div><div class="sidebar-section-children"><a href="BondStyle.html">BondStyle</a></div><div class="sidebar-section-children"><a href="BoxSpec.html">BoxSpec</a></div><div class="sidebar-section-children"><a href="CartoonStyleSpec.html">CartoonStyleSpec</a></div><div class="sidebar-section-children"><a href="ClickSphereStyleSpec.html">ClickSphereStyleSpec</a></div><div class="sidebar-section-children"><a href="CrossStyleSpec.html">CrossStyleSpec</a></div><div class="sidebar-section-children"><a href="CurveSpec.html">CurveSpec</a></div><div class="sidebar-section-children"><a href="CustomShapeSpec.html">CustomShapeSpec</a></div><div class="sidebar-section-children"><a href="CylinderSpec.html">CylinderSpec</a></div><div class="sidebar-section-children"><a href="DashedBondSpec.html">DashedBondSpec</a></div><div class="sidebar-section-children"><a href="FogSpec.html">FogSpec</a></div><div class="sidebar-section-children"><a href="IsoSurfaceSpec.html">IsoSurfaceSpec</a></div><div class="sidebar-section-children"><a href="LabelSpec.html">LabelSpec</a></div><div class="sidebar-section-children"><a href="LineSpec.html">LineSpec</a></div><div class="sidebar-section-children"><a href="LineStyleSpec.html">LineStyleSpec</a></div><div class="sidebar-section-children"><a href="OutlineStyle.html">OutlineStyle</a></div><div class="sidebar-section-children"><a href="ParserOptionsSpec.html">ParserOptionsSpec</a></div><div class="sidebar-section-children"><a href="ShapeSpec.html">ShapeSpec</a></div><div class="sidebar-section-children"><a href="SphereSpec.html">SphereSpec</a></div><div class="sidebar-section-children"><a href="SphereStyleSpec.html">SphereStyleSpec</a></div><div class="sidebar-section-children"><a href="StickStyleSpec.html">StickStyleSpec</a></div><div class="sidebar-section-children"><a href="SurfaceStyleSpec.html">SurfaceStyleSpec</a></div><div class="sidebar-section-children"><a href="UnitCellStyleSpec.html">UnitCellStyleSpec</a></div><div class="sidebar-section-children"><a href="ViewStyle.html">ViewStyle</a></div><div class="sidebar-section-children"><a href="ViewerGridSpec.html">ViewerGridSpec</a></div><div class="sidebar-section-children"><a href="ViewerSpec.html">ViewerSpec</a></div><div class="sidebar-section-children"><a href="VolumetricRendererSpec.html">VolumetricRendererSpec</a></div><div class="sidebar-section-children"><a href="WithinSelectionSpec.html">WithinSelectionSpec</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="jmKnIXRJjdjZ366ci7cdd"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#BCIF">BCIF</a></div><div class="sidebar-section-children"><a href="global.html#CAP">CAP</a></div><div class="sidebar-section-children"><a href="global.html#CDJSON">CDJSON</a></div><div class="sidebar-section-children"><a href="global.html#CIF">CIF</a></div><div class="sidebar-section-children"><a href="global.html#CUBE">CUBE</a></div><div class="sidebar-section-children"><a href="global.html#ColorSpec">ColorSpec</a></div><div class="sidebar-section-children"><a href="global.html#ColorschemeSpec">ColorschemeSpec</a></div><div class="sidebar-section-children"><a href="global.html#GRO">GRO</a></div><div class="sidebar-section-children"><a href="global.html#GradientSpec">GradientSpec</a></div><div class="sidebar-section-children"><a href="global.html#MMTFparser">MMTFparser</a></div><div class="sidebar-section-children"><a href="global.html#MOL2">MOL2</a></div><div class="sidebar-section-children"><a href="global.html#OFFSETS">OFFSETS</a></div><div class="sidebar-section-children"><a href="global.html#PDB">PDB</a></div><div class="sidebar-section-children"><a href="global.html#PQR">PQR</a></div><div class="sidebar-section-children"><a href="global.html#PRMTOP">PRMTOP</a></div><div class="sidebar-section-children"><a href="global.html#SDF">SDF</a></div><div class="sidebar-section-children"><a href="global.html#SurfaceType">SurfaceType</a></div><div class="sidebar-section-children"><a href="global.html#VASP">VASP</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div><div class="sidebar-section-children"><a href="global.html#assignPDBBonds">assignPDBBonds</a></div><div class="sidebar-section-children"><a href="global.html#builtinColorSchemes">builtinColorSchemes</a></div><div class="sidebar-section-children"><a href="global.html#builtinGradients">builtinGradients</a></div><div class="sidebar-section-children"><a href="global.html#conversionMatrix3">conversionMatrix3</a></div><div class="sidebar-section-children"><a href="global.html#createViewer">createViewer</a></div><div class="sidebar-section-children"><a href="global.html#createViewerGrid">createViewerGrid</a></div><div class="sidebar-section-children"><a href="global.html#decode">decode</a></div><div class="sidebar-section-children"><a href="global.html#dic">dic</a></div><div class="sidebar-section-children"><a href="global.html#download">download</a></div><div class="sidebar-section-children"><a href="global.html#elementColors">elementColors</a></div><div class="sidebar-section-children"><a href="global.html#get">get</a></div><div class="sidebar-section-children"><a href="global.html#getColorFromStyle">getColorFromStyle</a></div><div class="sidebar-section-children"><a href="global.html#getbin">getbin</a></div><div class="sidebar-section-children"><a href="global.html#parseV3000">parseV3000</a></div><div class="sidebar-section-children"><a href="global.html#setSyncSurface">setSyncSurface</a></div><div class="sidebar-section-children"><a href="global.html#ssColors">ssColors</a></div><div class="sidebar-section-children"><a href="global.html#syncSurface">syncSurface</a></div><div class="sidebar-section-children"><a href="global.html#viewers">viewers</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="https://3dmol.org/doc/index.html" target="">Documentation</a></div><div class="navbar-item"><a id="" href="tutorial-home.html" target="">Tutorials</a></div><div class="navbar-item"><a id="" href="https://github.com/3dmol/3Dmol.js" target="_blank">GitHub</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">WebGL_math_math.ts</h1></header><article><pre class="prettyprint source lang-js"><code>import { Quaternion } from "./Quaternion";
import { degToRad } from "./utils/degToRad";
import { clamp } from "./utils/clamp";
import { Sphere } from "../shapes";
var mRotation: Matrix4;
var mScale: Matrix4;
var x: Vector3;
var y: Vector3;
var z: Vector3;
/** @class
* @subcategory Math
* */
export class Matrix4 {
elements: Float32Array;
constructor(n11: Array<number>);
constructor(
n11?: number,
n12?: number,
n13?: number,
n14?: number,
n21?: number,
n22?: number,
n23?: number,
n24?: number,
n31?: number,
n32?: number,
n33?: number,
n34?: number,
n41?: number,
n42?: number,
n43?: number,
n44?: number
);
constructor(
n11: Array<number> | number = 1,
n12: number = 0,
n13: number = 0,
n14: number = 0,
n21: number = 0,
n22: number = 1,
n23: number = 0,
n24: number = 0,
n31: number = 0,
n32: number = 0,
n33: number = 1,
n34: number = 0,
n41: number = 0,
n42: number = 0,
n43: number = 0,
n44: number = 1
) {
if (typeof n11 !== "undefined" && typeof n11 !== "number") {
// passing list like initialization
this.elements = new Float32Array(n11);
} else {
this.elements = new Float32Array(16);
this.elements[0] = n11;
this.elements[4] = n12;
this.elements[8] = n13;
this.elements[12] = n14;
this.elements[1] = n21;
this.elements[5] = n22;
this.elements[9] = n23;
this.elements[13] = n24;
this.elements[2] = n31;
this.elements[6] = n32;
this.elements[10] = n33;
this.elements[14] = n34;
this.elements[3] = n41;
this.elements[7] = n42;
this.elements[11] = n43;
this.elements[15] = n44;
}
}
// eslint-disable-next-line no-unused-vars, class-methods-use-this
makeScale(x: any, y: any, z: any) {
throw new Error("Method not implemented.");
}
set(
n11: number,
n12: number,
n13: number,
n14: number,
n21: number,
n22: number,
n23: number,
n24: number,
n31: number,
n32: number,
n33: number,
n34: number,
n41: number,
n42: number,
n43: number,
n44: number
) {
const te = this.elements;
te[0] = n11;
te[4] = n12;
te[8] = n13;
te[12] = n14;
te[1] = n21;
te[5] = n22;
te[9] = n23;
te[13] = n24;
te[2] = n31;
te[6] = n32;
te[10] = n33;
te[14] = n34;
te[3] = n41;
te[7] = n42;
te[11] = n43;
te[15] = n44;
return this;
}
identity() {
this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
return this;
}
copy(m: { elements: any }) {
const me = m.elements;
this.set(
me[0],
me[4],
me[8],
me[12],
me[1],
me[5],
me[9],
me[13],
me[2],
me[6],
me[10],
me[14],
me[3],
me[7],
me[11],
me[15]
);
return this;
}
matrix3FromTopLeft() {
const te = this.elements;
return new Matrix3(
te[0],
te[4],
te[8],
te[1],
te[5],
te[9],
te[2],
te[6],
te[10]
);
}
setRotationFromEuler(v: Vector3, order?: string) {
const te = this.elements;
const { x, y, z } = v;
const a = Math.cos(x);
const b = Math.sin(x);
const c = Math.cos(y);
const d = Math.sin(y);
const e = Math.cos(z);
const f = Math.sin(z);
if (order === undefined || order === "XYZ") {
const ae = a * e;
const af = a * f;
const be = b * e;
const bf = b * f;
te[0] = c * e;
te[4] = -c * f;
te[8] = d;
te[1] = af + be * d;
te[5] = ae - bf * d;
te[9] = -b * c;
te[2] = bf - ae * d;
te[6] = be + af * d;
te[10] = a * c;
} else
console.error(`Error with matrix4 setRotationFromEuler. Order: ${order}`);
return this;
}
setRotationFromQuaternion(q: Quaternion) {
const te = this.elements;
const { x, y, z, w } = q;
const x2 = x + x;
const y2 = y + y;
const z2 = z + z;
const xx = x * x2;
const xy = x * y2;
const xz = x * z2;
const yy = y * y2;
const yz = y * z2;
const zz = z * z2;
const wx = w * x2;
const wy = w * y2;
const wz = w * z2;
te[0] = 1 - (yy + zz);
te[4] = xy - wz;
te[8] = xz + wy;
te[1] = xy + wz;
te[5] = 1 - (xx + zz);
te[9] = yz - wx;
te[2] = xz - wy;
te[6] = yz + wx;
te[10] = 1 - (xx + yy);
return this;
}
multiplyMatrices(a: { elements: any }, b: Matrix4) {
const ae = a.elements;
const be = b.elements;
const te = this.elements;
const a11 = ae[0];
const a12 = ae[4];
const a13 = ae[8];
const a14 = ae[12];
const a21 = ae[1];
const a22 = ae[5];
const a23 = ae[9];
const a24 = ae[13];
const a31 = ae[2];
const a32 = ae[6];
const a33 = ae[10];
const a34 = ae[14];
const a41 = ae[3];
const a42 = ae[7];
const a43 = ae[11];
const a44 = ae[15];
const b11 = be[0];
const b12 = be[4];
const b13 = be[8];
const b14 = be[12];
const b21 = be[1];
const b22 = be[5];
const b23 = be[9];
const b24 = be[13];
const b31 = be[2];
const b32 = be[6];
const b33 = be[10];
const b34 = be[14];
const b41 = be[3];
const b42 = be[7];
const b43 = be[11];
const b44 = be[15];
te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
return this;
}
multiplyScalar(s: number) {
const te = this.elements;
te[0] *= s;
te[4] *= s;
te[8] *= s;
te[12] *= s;
te[1] *= s;
te[5] *= s;
te[9] *= s;
te[13] *= s;
te[2] *= s;
te[6] *= s;
te[10] *= s;
te[14] *= s;
te[3] *= s;
te[7] *= s;
te[11] *= s;
te[15] *= s;
return this;
}
makeTranslation(x: any, y: any, z: any) {
this.set(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1);
return this;
}
// snap values close to integers to their integer value
// useful and identifying identity matrices
snap(digits: number) {
if (!digits) digits = 4;
const mult = 10 ** 4;
const te = this.elements;
for (let i = 0; i < 16; i++) {
const rounded = Math.round(te[i]);
if (rounded === Math.round(te[i] * mult) / mult) {
te[i] = rounded;
}
}
return this;
}
transpose() {
const te = this.elements;
let tmp: any;
tmp = te[1];
te[1] = te[4];
te[4] = tmp;
tmp = te[2];
te[2] = te[8];
te[8] = tmp;
tmp = te[6];
te[6] = te[9];
te[9] = tmp;
tmp = te[3];
te[3] = te[12];
te[12] = tmp;
tmp = te[7];
te[7] = te[13];
te[13] = tmp;
tmp = te[11];
te[11] = te[14];
te[14] = tmp;
return this;
}
setPosition(v: Vector3) {
const te = this.elements;
te[12] = v.x;
te[13] = v.y;
te[14] = v.z;
return this;
}
translate(v: Vector3) {
const te = this.elements;
te[12] += v.x;
te[13] += v.y;
te[14] += v.z;
return this;
}
getInverse(m: Matrix4, throwOnInvertible?: boolean) {
// based on
// http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
const te = this.elements;
const me = m.elements;
const n11 = me[0];
const n12 = me[4];
const n13 = me[8];
const n14 = me[12];
const n21 = me[1];
const n22 = me[5];
const n23 = me[9];
const n24 = me[13];
const n31 = me[2];
const n32 = me[6];
const n33 = me[10];
const n34 = me[14];
const n41 = me[3];
const n42 = me[7];
const n43 = me[11];
const n44 = me[15];
te[0] =
n23 * n34 * n42 -
n24 * n33 * n42 +
n24 * n32 * n43 -
n22 * n34 * n43 -
n23 * n32 * n44 +
n22 * n33 * n44;
te[4] =
n14 * n33 * n42 -
n13 * n34 * n42 -
n14 * n32 * n43 +
n12 * n34 * n43 +
n13 * n32 * n44 -
n12 * n33 * n44;
te[8] =
n13 * n24 * n42 -
n14 * n23 * n42 +
n14 * n22 * n43 -
n12 * n24 * n43 -
n13 * n22 * n44 +
n12 * n23 * n44;
te[12] =
n14 * n23 * n32 -
n13 * n24 * n32 -
n14 * n22 * n33 +
n12 * n24 * n33 +
n13 * n22 * n34 -
n12 * n23 * n34;
te[1] =
n24 * n33 * n41 -
n23 * n34 * n41 -
n24 * n31 * n43 +
n21 * n34 * n43 +
n23 * n31 * n44 -
n21 * n33 * n44;
te[5] =
n13 * n34 * n41 -
n14 * n33 * n41 +
n14 * n31 * n43 -
n11 * n34 * n43 -
n13 * n31 * n44 +
n11 * n33 * n44;
te[9] =
n14 * n23 * n41 -
n13 * n24 * n41 -
n14 * n21 * n43 +
n11 * n24 * n43 +
n13 * n21 * n44 -
n11 * n23 * n44;
te[13] =
n13 * n24 * n31 -
n14 * n23 * n31 +
n14 * n21 * n33 -
n11 * n24 * n33 -
n13 * n21 * n34 +
n11 * n23 * n34;
te[2] =
n22 * n34 * n41 -
n24 * n32 * n41 +
n24 * n31 * n42 -
n21 * n34 * n42 -
n22 * n31 * n44 +
n21 * n32 * n44;
te[6] =
n14 * n32 * n41 -
n12 * n34 * n41 -
n14 * n31 * n42 +
n11 * n34 * n42 +
n12 * n31 * n44 -
n11 * n32 * n44;
te[10] =
n12 * n24 * n41 -
n14 * n22 * n41 +
n14 * n21 * n42 -
n11 * n24 * n42 -
n12 * n21 * n44 +
n11 * n22 * n44;
te[14] =
n14 * n22 * n31 -
n12 * n24 * n31 -
n14 * n21 * n32 +
n11 * n24 * n32 +
n12 * n21 * n34 -
n11 * n22 * n34;
te[3] =
n23 * n32 * n41 -
n22 * n33 * n41 -
n23 * n31 * n42 +
n21 * n33 * n42 +
n22 * n31 * n43 -
n21 * n32 * n43;
te[7] =
n12 * n33 * n41 -
n13 * n32 * n41 +
n13 * n31 * n42 -
n11 * n33 * n42 -
n12 * n31 * n43 +
n11 * n32 * n43;
te[11] =
n13 * n22 * n41 -
n12 * n23 * n41 -
n13 * n21 * n42 +
n11 * n23 * n42 +
n12 * n21 * n43 -
n11 * n22 * n43;
te[15] =
n12 * n23 * n31 -
n13 * n22 * n31 +
n13 * n21 * n32 -
n11 * n23 * n32 -
n12 * n21 * n33 +
n11 * n22 * n33;
const det = n11 * te[0] + n21 * te[4] + n31 * te[8] + n41 * te[12];
if (det === 0) {
const msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0";
if (throwOnInvertible || false) {
throw new Error(msg);
} else {
console.warn(msg);
}
this.identity();
return this;
}
this.multiplyScalar(1 / det);
return this;
}
isReflected() {
const te = this.elements;
const m0 = te[0];
const m3 = te[4];
const m6 = te[8];
const m1 = te[1];
const m4 = te[5];
const m7 = te[9];
const m2 = te[2];
const m5 = te[6];
const m8 = te[10];
const determinant =
m0 * m4 * m8 + // +aei
m1 * m5 * m6 + // +bfg
m2 * m3 * m7 - // +cdh
m2 * m4 * m6 - // -ceg
m1 * m3 * m8 - // -bdi
m0 * m5 * m7; // -afh
return determinant < 0;
}
scale(v: { x?: any; y?: any; z?: any }) {
const te = this.elements;
const { x } = v;
const { y } = v;
const { z } = v;
te[0] *= x;
te[4] *= y;
te[8] *= z;
te[1] *= x;
te[5] *= y;
te[9] *= z;
te[2] *= x;
te[6] *= y;
te[10] *= z;
te[3] *= x;
te[7] *= y;
te[11] *= z;
return this;
}
getMaxScaleOnAxis() {
const te = this.elements;
const scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
const scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
const scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
return Math.sqrt(Math.max(scaleXSq, Math.max(scaleYSq, scaleZSq)));
}
makeFrustum(
left: number,
right: number,
bottom: number,
top: number,
near: number,
far: number
) {
const te = this.elements;
const x = (2 * near) / (right - left);
const y = (2 * near) / (top - bottom);
const a = (right + left) / (right - left);
const b = (top + bottom) / (top - bottom);
const c = -(far + near) / (far - near);
const d = (-2 * far * near) / (far - near);
te[0] = x;
te[4] = 0;
te[8] = a;
te[12] = 0;
te[1] = 0;
te[5] = y;
te[9] = b;
te[13] = 0;
te[2] = 0;
te[6] = 0;
te[10] = c;
te[14] = d;
te[3] = 0;
te[7] = 0;
te[11] = -1;
te[15] = 0;
return this;
}
makePerspective(fov: number, aspect: number, near: number, far: any) {
const ymax = near * Math.tan(degToRad(fov * 0.5));
const ymin = -ymax;
const xmin = ymin * aspect;
const xmax = ymax * aspect;
return this.makeFrustum(xmin, xmax, ymin, ymax, near, far);
}
makeOrthographic(
left: number,
right: number,
top: number,
bottom: number,
near: number,
far: number
) {
const te = this.elements;
const w = 1.0 / (right - left);
const h = 1.0 / (top - bottom);
const p = 1.0 / (far - near);
const x = (right + left) * w;
const y = (top + bottom) * h;
const z = (far + near) * p;
te[0] = 2 * w;
te[4] = 0;
te[8] = 0;
te[12] = -x;
te[1] = 0;
te[5] = 2 * h;
te[9] = 0;
te[13] = -y;
te[2] = 0;
te[6] = 0;
te[10] = -2 * p;
te[14] = -z;
te[3] = 0;
te[7] = 0;
te[11] = 0;
te[15] = 1;
return this;
}
isEqual(m: { elements: any }) {
const me = m.elements;
const te = this.elements;
if (
te[0] === me[0] &&
te[4] === me[4] &&
te[8] === me[8] &&
te[12] === me[12] &&
te[1] === me[1] &&
te[5] === me[5] &&
te[9] === me[9] &&
te[13] === me[13] &&
te[2] === me[2] &&
te[6] === me[6] &&
te[10] === me[10] &&
te[14] === me[14] &&
te[3] === me[3] &&
te[7] === me[7] &&
te[11] === me[11] &&
te[15] === me[15]
) {
return true;
}
return false;
}
clone() {
const te = this.elements;
return new Matrix4(
te[0],
te[4],
te[8],
te[12],
te[1],
te[5],
te[9],
te[13],
te[2],
te[6],
te[10],
te[14],
te[3],
te[7],
te[11],
te[15]
);
}
isIdentity() {
const te = this.elements;
if (
te[0] === 1 &&
te[4] === 0 &&
te[8] === 0 &&
te[12] === 0 &&
te[1] === 0 &&
te[5] === 1 &&
te[9] === 0 &&
te[13] === 0 &&
te[2] === 0 &&
te[6] === 0 &&
te[10] === 1 &&
te[14] === 0 &&
te[3] === 0 &&
te[7] === 0 &&
te[11] === 0 &&
te[15] === 1
) {
return true;
}
return false;
}
// return true if elements are with digits of identity
isNearlyIdentity(digits: any) {
const snapped = this.clone().snap(digits);
return snapped.isIdentity();
}
getScale(scale?: Vector3): Vector3 {
const te = this.elements;
scale = scale || new Vector3();
// grab the axis vectors
x.set(te[0], te[1], te[2]);
y.set(te[4], te[5], te[6]);
z.set(te[8], te[9], te[10]);
scale.x = x.length();
scale.y = y.length();
scale.z = z.length();
return scale;
}
lookAt(eye: Vector3, target: Vector3, up: Vector3) {
const te = this.elements;
z.subVectors(eye, target).normalize();
if (z.length() === 0) {
z.z = 1;
}
x.crossVectors(up, z).normalize();
if (x.length() === 0) {
z.x += 0.0001;
x.crossVectors(up, z).normalize();
}
y.crossVectors(z, x);
te[0] = x.x;
te[4] = y.x;
te[8] = z.x;
te[1] = x.y;
te[5] = y.y;
te[9] = z.y;
te[2] = x.z;
te[6] = y.z;
te[10] = z.z;
return this;
}
compose(translation: Vector3, rotation: Quaternion, scale: Vector3) {
const te = this.elements;
mRotation.identity();
mRotation.setRotationFromQuaternion(rotation);
mScale.makeScale(scale.x, scale.y, scale.z);
this.multiplyMatrices(mRotation, mScale);
te[12] = translation.x;
te[13] = translation.y;
te[14] = translation.z;
return this;
}
}
mRotation = new Matrix4();
mScale = new Matrix4();
/**
* @interface
*/
export interface XYZ {
/** */
x: number;
/** */
y: number;
/** */
z: number;
}
/** @class
* @subcategory Math
* */
export class Vector3 {
// unaccounted for assignents to vector3 properties in other parts of the code
// look in glcartoon.js for example
color?: any;
resi?: any;
style?: any;
smoothen?: any;
atom?: any;
skip?: any;
atomid?: undefined;
x: number;
y: number;
z: number;
constructor(x?: number, y?: number, z?: number) {
this.x = x || 0.0;
this.y = y || 0.0;
this.z = z || 0.0;
this.atomid = undefined;
}
set(x: any, y: any, z: any) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
copy(v: { x: any; y: any; z: any }) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
}
add(v: { x: any; y: any; z: any }) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
}
addVectors(a: { x: any; y: any; z: any }, b: { x: any; y: any; z: any }) {
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
return this;
}
multiplyVectors(
a: { x: number; y: number; z: number },
b: { x: number; y: number; z: number }
) {
// elementwise
this.x = a.x * b.x;
this.y = a.y * b.y;
this.z = a.z * b.z;
return this;
}
sub(v: { x: number; y: number; z: number }) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
return this;
}
subVectors(
a: { x: number; y: number; z: number },
b: { x: number; y: number; z: number }
) {
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
return this;
}
multiplyScalar(s: number) {
this.x *= s;
this.y *= s;
this.z *= s;
return this;
}
divideScalar(s: number) {
if (s !== 0) {
this.x /= s;
this.y /= s;
this.z /= s;
} else {
this.x = 0;
this.y = 0;
this.z = 0;
}
return this;
}
// accumulate maximum
max(s: { x: number; y: number; z: number }) {
this.x = Math.max(this.x, s.x);
this.y = Math.max(this.y, s.y);
this.z = Math.max(this.z, s.z);
return this;
}
// accumulate min
min(s: { x: number; y: number; z: number }) {
this.x = Math.min(this.x, s.x);
this.y = Math.min(this.y, s.y);
this.z = Math.min(this.z, s.z);
return this;
}
distanceTo(v: any) {
return Math.sqrt(this.distanceToSquared(v));
}
distanceToSquared(v: { x: number; y: number; z: number }) {
const dx = this.x - v.x;
const dy = this.y - v.y;
const dz = this.z - v.z;
return dx * dx + dy * dy + dz * dz;
}
applyMatrix3(m: { elements: any }) {
const { x } = this;
const { y } = this;
const { z } = this;
const e = m.elements;
// column major ordering
this.x = e[0] * x + e[3] * y + e[6] * z;
this.y = e[1] * x + e[4] * y + e[7] * z;
this.z = e[2] * x + e[5] * y + e[8] * z;
return this;
}
applyMatrix4(m: { elements: any }) {
const { x } = this;
const { y } = this;
const { z } = this;
const e = m.elements;
this.x = e[0] * x + e[4] * y + e[8] * z + e[12];
this.y = e[1] * x + e[5] * y + e[9] * z + e[13];
this.z = e[2] * x + e[6] * y + e[10] * z + e[14];
return this;
}
applyProjection(m: { elements: any }) {
// input: Matrix4 projection matrix
const { x } = this;
const { y } = this;
const { z } = this;
const e = m.elements;
const d = e[3] * x + e[7] * y + e[11] * z + e[15];
this.x = (e[0] * x + e[4] * y + e[8] * z + e[12]) / d;
this.y = (e[1] * x + e[5] * y + e[9] * z + e[13]) / d;
this.z = (e[2] * x + e[6] * y + e[10] * z + e[14]) / d;
return this;
}
applyQuaternion(q: Quaternion): Vector3 {
// save values
const { x } = this;
const { y } = this;
const { z } = this;
const qx = q.x;
const qy = q.y;
const qz = q.z;
const qw = q.w;
// compute this as
// t = 2 * cross(q.xyz, v)
// newv = v + q.w * t + cross(q.xyz, t)
// this from molecularmusings
// http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/
const t: { x?: number; y?: number; z?: number } = {};
t.x = 2 * (y * qz - z * qy);
t.y = 2 * (z * qx - x * qz);
t.z = 2 * (x * qy - y * qx);
// cross t with q
const t2: { x?: number; y?: number; z?: number } = {};
t2.x = t.y * qz - t.z * qy;
t2.y = t.z * qx - t.x * qz;
t2.z = t.x * qy - t.y * qx;
this.x = x + qw * t.x + t2.x;
this.y = y + qw * t.y + t2.y;
this.z = z + qw * t.z + t2.z;
return this;
}
negate() {
return this.multiplyScalar(-1);
}
dot(v: Vector3) {
return this.x * v.x + this.y * v.y + this.z * v.z;
}
length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
lengthSq() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
normalize() {
return this.divideScalar(this.length());
}
cross(v: Vector3) {
const { x } = this;
const { y } = this;
const { z } = this;
this.x = y * v.z - z * v.y;
this.y = z * v.x - x * v.z;
this.z = x * v.y - y * v.x;
return this;
}
crossVectors(a: Vector3, b: Vector3) {
this.x = a.y * b.z - a.z * b.y;
this.y = a.z * b.x - a.x * b.z;
this.z = a.x * b.y - a.y * b.x;
return this;
}
equals(b: Vector3) {
return this.x == b.x && this.y == b.y && this.z == b.z;
}
getPositionFromMatrix(m: Matrix4) {
this.x = m.elements[12];
this.y = m.elements[13];
this.z = m.elements[14];
return this;
}
setEulerFromRotationMatrix(m: Matrix4, order: string) {
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
const te = m.elements;
const m11 = te[0];
const m12 = te[4];
const m13 = te[8];
// var m21 = te[1];
const m22 = te[5];
const m23 = te[9];
// var m31 = te[2];
const m32 = te[6];
const m33 = te[10];
if (order === undefined || order === "XYZ") {
this.y = Math.asin(clamp(m13, -1, 1));
if (Math.abs(m13) < 0.99999) {
this.x = Math.atan2(-m23, m33);
this.z = Math.atan2(-m12, m11);
} else {
this.x = Math.atan2(m32, m22);
this.z = 0;
}
} else {
console.error(
`Error with vector's setEulerFromRotationMatrix: Unknown order: ${order}`
);
}
return this;
}
rotateAboutVector(axis: Vector3, ang: number) {
axis.normalize();
const cosang = Math.cos(ang);
const sinang = Math.sin(ang);
// Rodrigues' rotation formula, from wikipedia
const term1 = this.clone().multiplyScalar(cosang);
const term2 = axis.clone().cross(this).multiplyScalar(sinang);
const term3 = axis
.clone()
.multiplyScalar(axis.clone().dot(this))
.multiplyScalar(1 - cosang);
const rot = term1.add(term2).add(term3);
this.x = rot.x;
this.y = rot.y;
this.z = rot.z;
return this;
}
setFromMatrixPosition(m: { elements: any }) {
const e = m.elements;
this.x = e[12];
this.y = e[13];
this.z = e[14];
return this;
}
// unproject is defined after Matrix4
transformDirection(m: { elements: any }) {
// input: THREE.Matrix4 affine matrix
// vector interpreted as a direction
const { x } = this;
const { y } = this;
const { z } = this;
const e = m.elements;
this.x = e[0] * x + e[4] * y + e[8] * z;
this.y = e[1] * x + e[5] * y + e[9] * z;
this.z = e[2] * x + e[6] * y + e[10] * z;
return this.normalize();
}
clone() {
return new Vector3(this.x, this.y, this.z);
}
unproject(camera: { matrixWorld: any; projectionMatrix: any }) {
const mat4 = mRotation;
mat4.multiplyMatrices(
camera.matrixWorld,
mat4.getInverse(camera.projectionMatrix)
);
return this.applyMatrix4(mat4);
}
}
x = new Vector3();
y = new Vector3();
z = new Vector3();
/*
* @interface Matrix3
*/
export interface Matrix3 {
elements: Float32Array;
}
/** @class
* @subcategory Math
* */
export class Matrix3 {
constructor(
n11: number = 1,
n12: number = 0,
n13: number = 0,
n21: number = 0,
n22: number = 1,
n23: number = 0,
n31: number = 0,
n32: number = 0,
n33: number = 1
) {
this.elements = new Float32Array(9);
this.set(n11, n12, n13, n21, n22, n23, n31, n32, n33);
}
set(
n11: number,
n12: number,
n13: number,
n21: number,
n22: number,
n23: number,
n31: number,
n32: number,
n33: number
) {
const te = this.elements;
te[0] = n11;
te[3] = n12;
te[6] = n13;
te[1] = n21;
te[4] = n22;
te[7] = n23;
te[2] = n31;
te[5] = n32;
te[8] = n33;
return this;
}
identity() {
this.set(1, 0, 0, 0, 1, 0, 0, 0, 1);
return this;
}
copy(m: { elements: any }) {
const me = m.elements;
this.set(me[0], me[3], me[6], me[1], me[4], me[7], me[2], me[5], me[8]);
}
multiplyScalar(s: number) {
const te = this.elements;
te[0] *= s;
te[3] *= s;
te[6] *= s;
te[1] *= s;
te[4] *= s;
te[7] *= s;
te[2] *= s;
te[5] *= s;
te[8] *= s;
return this;
}
getInverse3(matrix: { elements: any }) {
// input: Matrix3
const me = matrix.elements;
const te = this.elements;
te[0] = me[4] * me[8] - me[5] * me[7];
te[3] = me[6] * me[5] - me[3] * me[8];
te[6] = me[3] * me[7] - me[6] * me[4];
te[1] = me[7] * me[2] - me[1] * me[8];
te[4] = me[0] * me[8] - me[6] * me[2];
te[7] = me[1] * me[6] - me[0] * me[7];
te[2] = me[1] * me[5] - me[2] * me[4];
te[5] = me[2] * me[3] - me[0] * me[5];
te[8] = me[0] * me[4] - me[1] * me[3];
const det = me[0] * te[0] + me[3] * te[1] + me[6] * te[2];
this.multiplyScalar(1.0 / det);
return this;
}
getInverse(matrix: { elements: any }, throwOnInvertible: any) {
// input: Matrix4
const me = matrix.elements;
const te = this.elements;
te[0] = me[10] * me[5] - me[6] * me[9];
te[1] = -me[10] * me[1] + me[2] * me[9];
te[2] = me[6] * me[1] - me[2] * me[5];
te[3] = -me[10] * me[4] + me[6] * me[8];
te[4] = me[10] * me[0] - me[2] * me[8];
te[5] = -me[6] * me[0] + me[2] * me[4];
te[6] = me[9] * me[4] - me[5] * me[8];
te[7] = -me[9] * me[0] + me[1] * me[8];
te[8] = me[5] * me[0] - me[1] * me[4];
const det = me[0] * te[0] + me[1] * te[3] + me[2] * te[6];
// no inverse
if (det === 0) {
const msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0";
if (throwOnInvertible || false) {
throw new Error(msg);
} else {
console.warn(msg);
}
this.identity();
return this;
}
this.multiplyScalar(1.0 / det);
return this;
}
// https://en.wikipedia.org/wiki/Determinant
getDeterminant() {
const m = this.elements;
/*
* |a b c| |d e f| |g h i|
*/
const determinant =
m[0] * m[4] * m[8] + // +aei
m[1] * m[5] * m[6] + // +bfg
m[2] * m[3] * m[7] - // +cdh
m[2] * m[4] * m[6] - // -ceg
m[1] * m[3] * m[8] - // -bdi
m[0] * m[5] * m[7]; // -afh
return determinant;
}
transpose() {
let tmp: any;
const m = this.elements;
tmp = m[1];
m[1] = m[3];
m[3] = tmp;
tmp = m[2];
m[2] = m[6];
m[6] = tmp;
tmp = m[5];
m[5] = m[7];
m[7] = tmp;
return this;
}
clone() {
const te = this.elements;
return new Matrix3(
te[0],
te[3],
te[6],
te[1],
te[4],
te[7],
te[2],
te[5],
te[8]
);
}
getMatrix4() {
const m = this.elements;
return new Matrix4(
m[0],
m[3],
m[6],
0,
m[1],
m[4],
m[7],
0,
m[2],
m[5],
m[8],
0
);
}
}
/** @class
* @subcategory Math
* */
export class Ray {
origin: Vector3;
direction: Vector3;
constructor(origin?: Vector3, direction?: Vector3) {
this.origin = origin !== undefined ? origin : new Vector3();
this.direction = direction !== undefined ? direction : new Vector3();
}
set(origin: Vector3, direction: Vector3) {
this.origin.copy(origin);
this.direction.copy(direction);
return this;
}
copy(ray: Ray) {
this.origin.copy(ray.origin);
this.direction.copy(ray.direction);
return this;
}
at(t: number, optionalTarget: Vector3) {
const result = optionalTarget || new Vector3();
return result.copy(this.direction).multiplyScalar(t).add(this.origin);
}
recast(t: any) {
const v1 = x;
this.origin.copy(this.at(t, v1));
return this;
}
closestPointToPoint(point: Vector3, optionalTarget: Vector3) {
const result = optionalTarget || new Vector3();
result.subVectors(point, this.origin);
const directionDistance = result.dot(this.direction);
// returns a point on this ray
return result
.copy(this.direction)
.multiplyScalar(directionDistance)
.add(this.origin);
}
distanceToPoint(point: Vector3) {
const v1 = x;
const directionDistance = v1
.subVectors(point, this.origin)
.dot(this.direction);
v1.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
return v1.distanceTo(point);
}
// eslint-disable-next-line class-methods-use-this
isIntersectionCylinder() {}
isIntersectionSphere(sphere: Sphere) {
return this.distanceToPoint(sphere.center) <= sphere.radius;
}
isIntersectionPlane(plane: any) {
const denominator = plane.normal.dot(this.direction);
// plane and ray are not perpendicular
if (denominator !== 0) return true;
if (plane.distanceToPoint(this.origin) === 0) return true;
return false;
}
distanceToPlane(plane: any) {
const denominator = plane.normal.dot(this.direction);
if (denominator === 0) {
// line is coplanar
if (plane.distanceToPoint(this.origin) === 0) return 0;
// ray is parallel
return undefined;
}
const t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
return t;
}
intersectPlane(plane: any, optionalTarget: any) {
const t = this.distanceToPlane(plane);
if (t === undefined) return undefined;
return this.at(t, optionalTarget);
}
applyMatrix4(matrix4: any) {
this.direction.add(this.origin).applyMatrix4(matrix4);
this.origin.applyMatrix4(matrix4);
this.direction.sub(this.origin);
return this;
}
clone() {
return new Ray().copy(this);
}
}
</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper">3Dmol.js © 2019-2024 | <a href="https://pitt.edu/" target="_blank">University of Pittsburgh</a> | <a href="https://github.com/3dmol/3Dmol.js/blob/master/LICENSE" target="_blank">License</a></div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"