@google/model-viewer
Version:
Easily display interactive 3D models on the web and in AR!
1,736 lines (1,328 loc) • 2.16 MB
JavaScript
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const t$2=globalThis,e$2=t$2.ShadowRoot&&(void 0===t$2.ShadyCSS||t$2.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$1=Symbol(),o$3=new WeakMap;let n$4 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$1)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$2&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$3.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$3.set(s,t));}return t}toString(){return this.cssText}};const r$4=t=>new n$4("string"==typeof t?t:t+"",void 0,s$1),S$1=(s,o)=>{if(e$2)s.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const e of o){const o=document.createElement("style"),n=t$2.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$3=e$2?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$4(e)})(t):t;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/const{is:i$3,defineProperty:e$1,getOwnPropertyDescriptor:r$3,getOwnPropertyNames:h$1,getOwnPropertySymbols:o$2,getPrototypeOf:n$3}=Object,a$2=globalThis,c$2=a$2.trustedTypes,l$1=c$2?c$2.emptyScript:"",p$1=a$2.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$2={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$3(t,s),y$1={attribute:true,type:String,converter:u$2,reflect:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$2.litPropertyMetadata??=new WeakMap;let b$1 = class b extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=y$1){if(s.state&&(s.attribute=false),this._$Ei(),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),r=this.getPropertyDescriptor(t,i,s);void 0!==r&&e$1(this.prototype,t,r);}}static getPropertyDescriptor(t,s,i){const{get:e,set:h}=r$3(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get(){return e?.call(this)},set(s){const r=e?.call(this);h.call(this,s),this.requestUpdate(t,r,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??y$1}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$3(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...h$1(t),...o$2(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$3(s));}else void 0!==s&&i.push(c$3(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S$1(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach((t=>t.hostConnected?.()));}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()));}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$EC(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:u$2).toAttribute(s,i.type);this._$Em=t,null==r?this.removeAttribute(e):this.setAttribute(e,r),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u$2;this._$Em=e,this[e]=r.fromAttribute(s,t.type),this._$Em=null;}}requestUpdate(t,s,i){if(void 0!==t){if(i??=this.constructor.getPropertyOptions(t),!(i.hasChanged??f$1)(this[t],s))return;this.P(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$ET());}P(t,s,i){this._$AL.has(t)||this._$AL.set(t,s),true===i.reflect&&this._$Em!==t&&(this._$Ej??=new Set).add(t);}async _$ET(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t) true!==i.wrapped||this._$AL.has(s)||void 0===this[s]||this.P(s,this[s],i);}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach((t=>t.hostUpdate?.())),this.update(s)):this._$EU();}catch(s){throw t=false,this._$EU(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach((t=>t.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EU(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Ej&&=this._$Ej.forEach((t=>this._$EC(t,this[t]))),this._$EU();}updated(t){}firstUpdated(t){}};b$1.elementStyles=[],b$1.shadowRootOptions={mode:"open"},b$1[d$1("elementProperties")]=new Map,b$1[d$1("finalized")]=new Map,p$1?.({ReactiveElement:b$1}),(a$2.reactiveElementVersions??=[]).push("2.0.4");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/const o$1={attribute:true,type:String,converter:u$2,reflect:false,hasChanged:f$1},r$2=(t=o$1,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.P(o,void 0,t),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n$2(t){return (e,o)=>"object"==typeof o?r$2(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,r?{...t,wrapped:true}:t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
/**
* @license
* Copyright 2010-2025 Three.js Authors
* SPDX-License-Identifier: MIT
*/
const REVISION = '174';
const CullFaceNone = 0;
const CullFaceBack = 1;
const CullFaceFront = 2;
const PCFShadowMap = 1;
const PCFSoftShadowMap = 2;
const VSMShadowMap = 3;
const FrontSide = 0;
const BackSide = 1;
const DoubleSide = 2;
const NoBlending = 0;
const NormalBlending = 1;
const AdditiveBlending = 2;
const SubtractiveBlending = 3;
const MultiplyBlending = 4;
const CustomBlending = 5;
const AddEquation = 100;
const SubtractEquation = 101;
const ReverseSubtractEquation = 102;
const MinEquation = 103;
const MaxEquation = 104;
const ZeroFactor = 200;
const OneFactor = 201;
const SrcColorFactor = 202;
const OneMinusSrcColorFactor = 203;
const SrcAlphaFactor = 204;
const OneMinusSrcAlphaFactor = 205;
const DstAlphaFactor = 206;
const OneMinusDstAlphaFactor = 207;
const DstColorFactor = 208;
const OneMinusDstColorFactor = 209;
const SrcAlphaSaturateFactor = 210;
const ConstantColorFactor = 211;
const OneMinusConstantColorFactor = 212;
const ConstantAlphaFactor = 213;
const OneMinusConstantAlphaFactor = 214;
const NeverDepth = 0;
const AlwaysDepth = 1;
const LessDepth = 2;
const LessEqualDepth = 3;
const EqualDepth = 4;
const GreaterEqualDepth = 5;
const GreaterDepth = 6;
const NotEqualDepth = 7;
const MultiplyOperation = 0;
const MixOperation = 1;
const AddOperation = 2;
const NoToneMapping = 0;
const LinearToneMapping = 1;
const ReinhardToneMapping = 2;
const CineonToneMapping = 3;
const ACESFilmicToneMapping = 4;
const CustomToneMapping = 5;
const AgXToneMapping = 6;
const NeutralToneMapping = 7;
const AttachedBindMode = 'attached';
const DetachedBindMode = 'detached';
const UVMapping = 300;
const CubeReflectionMapping = 301;
const CubeRefractionMapping = 302;
const EquirectangularReflectionMapping = 303;
const EquirectangularRefractionMapping = 304;
const CubeUVReflectionMapping = 306;
const RepeatWrapping = 1000;
const ClampToEdgeWrapping = 1001;
const MirroredRepeatWrapping = 1002;
const NearestFilter = 1003;
const NearestMipmapNearestFilter = 1004;
const NearestMipmapLinearFilter = 1005;
const LinearFilter = 1006;
const LinearMipmapNearestFilter = 1007;
const LinearMipmapLinearFilter = 1008;
const LinearMipMapLinearFilter = 1008;
const UnsignedByteType = 1009;
const ByteType = 1010;
const ShortType = 1011;
const UnsignedShortType = 1012;
const IntType = 1013;
const UnsignedIntType = 1014;
const FloatType = 1015;
const HalfFloatType = 1016;
const UnsignedShort4444Type = 1017;
const UnsignedShort5551Type = 1018;
const UnsignedInt248Type = 1020;
const UnsignedInt5999Type = 35902;
const AlphaFormat = 1021;
const RGBFormat = 1022;
const RGBAFormat = 1023;
const LuminanceFormat = 1024;
const LuminanceAlphaFormat = 1025;
const DepthFormat = 1026;
const DepthStencilFormat = 1027;
const RedFormat = 1028;
const RedIntegerFormat = 1029;
const RGFormat = 1030;
const RGIntegerFormat = 1031;
const RGBAIntegerFormat = 1033;
const RGB_S3TC_DXT1_Format = 33776;
const RGBA_S3TC_DXT1_Format = 33777;
const RGBA_S3TC_DXT3_Format = 33778;
const RGBA_S3TC_DXT5_Format = 33779;
const RGB_PVRTC_4BPPV1_Format = 35840;
const RGB_PVRTC_2BPPV1_Format = 35841;
const RGBA_PVRTC_4BPPV1_Format = 35842;
const RGBA_PVRTC_2BPPV1_Format = 35843;
const RGB_ETC1_Format = 36196;
const RGB_ETC2_Format = 37492;
const RGBA_ETC2_EAC_Format = 37496;
const RGBA_ASTC_4x4_Format = 37808;
const RGBA_ASTC_5x4_Format = 37809;
const RGBA_ASTC_5x5_Format = 37810;
const RGBA_ASTC_6x5_Format = 37811;
const RGBA_ASTC_6x6_Format = 37812;
const RGBA_ASTC_8x5_Format = 37813;
const RGBA_ASTC_8x6_Format = 37814;
const RGBA_ASTC_8x8_Format = 37815;
const RGBA_ASTC_10x5_Format = 37816;
const RGBA_ASTC_10x6_Format = 37817;
const RGBA_ASTC_10x8_Format = 37818;
const RGBA_ASTC_10x10_Format = 37819;
const RGBA_ASTC_12x10_Format = 37820;
const RGBA_ASTC_12x12_Format = 37821;
const RGBA_BPTC_Format = 36492;
const RGB_BPTC_SIGNED_Format = 36494;
const RGB_BPTC_UNSIGNED_Format = 36495;
const RED_RGTC1_Format = 36283;
const SIGNED_RED_RGTC1_Format = 36284;
const RED_GREEN_RGTC2_Format = 36285;
const SIGNED_RED_GREEN_RGTC2_Format = 36286;
const LoopOnce = 2200;
const LoopRepeat = 2201;
const LoopPingPong = 2202;
const InterpolateDiscrete = 2300;
const InterpolateLinear = 2301;
const InterpolateSmooth = 2302;
const ZeroCurvatureEnding = 2400;
const ZeroSlopeEnding = 2401;
const WrapAroundEnding = 2402;
const NormalAnimationBlendMode = 2500;
const AdditiveAnimationBlendMode = 2501;
const TrianglesDrawMode = 0;
const TriangleStripDrawMode = 1;
const TriangleFanDrawMode = 2;
const BasicDepthPacking = 3200;
const RGBADepthPacking = 3201;
const TangentSpaceNormalMap = 0;
const ObjectSpaceNormalMap = 1;
// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available.
const NoColorSpace = '';
const SRGBColorSpace = 'srgb';
const LinearSRGBColorSpace = 'srgb-linear';
const LinearTransfer = 'linear';
const SRGBTransfer = 'srgb';
const KeepStencilOp = 7680;
const AlwaysStencilFunc = 519;
const NeverCompare = 512;
const LessCompare = 513;
const EqualCompare = 514;
const LessEqualCompare = 515;
const GreaterCompare = 516;
const NotEqualCompare = 517;
const GreaterEqualCompare = 518;
const AlwaysCompare = 519;
const StaticDrawUsage = 35044;
const GLSL3 = '300 es';
const WebGLCoordinateSystem = 2000;
const WebGPUCoordinateSystem = 2001;
/**
* This modules allows to dispatch event objects on custom JavaScript objects.
*
* Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/}
*
* Code Example:
* ```js
* class Car extends EventDispatcher {
* start() {
* this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } );
* }
*};
*
* // Using events with the custom object
* const car = new Car();
* car.addEventListener( 'start', function ( event ) {
* alert( event.message );
* } );
*
* car.start();
* ```
*/
class EventDispatcher {
/**
* Adds the given event listener to the given event type.
*
* @param {string} type - The type of event to listen to.
* @param {Function} listener - The function that gets called when the event is fired.
*/
addEventListener( type, listener ) {
if ( this._listeners === undefined ) this._listeners = {};
const listeners = this._listeners;
if ( listeners[ type ] === undefined ) {
listeners[ type ] = [];
}
if ( listeners[ type ].indexOf( listener ) === -1 ) {
listeners[ type ].push( listener );
}
}
/**
* Returns `true` if the given event listener has been added to the given event type.
*
* @param {string} type - The type of event.
* @param {Function} listener - The listener to check.
* @return {boolean} Whether the given event listener has been added to the given event type.
*/
hasEventListener( type, listener ) {
const listeners = this._listeners;
if ( listeners === undefined ) return false;
return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== -1;
}
/**
* Removes the given event listener from the given event type.
*
* @param {string} type - The type of event.
* @param {Function} listener - The listener to remove.
*/
removeEventListener( type, listener ) {
const listeners = this._listeners;
if ( listeners === undefined ) return;
const listenerArray = listeners[ type ];
if ( listenerArray !== undefined ) {
const index = listenerArray.indexOf( listener );
if ( index !== -1 ) {
listenerArray.splice( index, 1 );
}
}
}
/**
* Dispatches an event object.
*
* @param {Object} event - The event that gets fired.
*/
dispatchEvent( event ) {
const listeners = this._listeners;
if ( listeners === undefined ) return;
const listenerArray = listeners[ event.type ];
if ( listenerArray !== undefined ) {
event.target = this;
// Make a copy, in case listeners are removed while iterating.
const array = listenerArray.slice( 0 );
for ( let i = 0, l = array.length; i < l; i ++ ) {
array[ i ].call( this, event );
}
event.target = null;
}
}
}
const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ];
let _seed = 1234567;
const DEG2RAD = Math.PI / 180;
const RAD2DEG = 180 / Math.PI;
/**
* Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier}
* (universally unique identifier).
*
* @return {string} The UUID.
*/
function generateUUID() {
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
const d0 = Math.random() * 0xffffffff | 0;
const d1 = Math.random() * 0xffffffff | 0;
const d2 = Math.random() * 0xffffffff | 0;
const d3 = Math.random() * 0xffffffff | 0;
const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
// .toLowerCase() here flattens concatenated strings to save heap memory space.
return uuid.toLowerCase();
}
/**
* Clamps the given value between min and max.
*
* @param {number} value - The value to clamp.
* @param {number} min - The min value.
* @param {number} max - The max value.
* @return {number} The clamped value.
*/
function clamp$1( value, min, max ) {
return Math.max( min, Math.min( max, value ) );
}
/**
* Computes the Euclidean modulo of the given parameters that
* is `( ( n % m ) + m ) % m`.
*
* @param {number} n - The first parameter.
* @param {number} m - The second parameter.
* @return {number} The Euclidean modulo.
*/
function euclideanModulo( n, m ) {
// https://en.wikipedia.org/wiki/Modulo_operation
return ( ( n % m ) + m ) % m;
}
/**
* Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>`
* for the given value.
*
* @param {number} x - The value to be mapped.
* @param {number} a1 - Minimum value for range A.
* @param {number} a2 - Maximum value for range A.
* @param {number} b1 - Minimum value for range B.
* @param {number} b2 - Maximum value for range B.
* @return {number} The mapped value.
*/
function mapLinear( x, a1, a2, b1, b2 ) {
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
}
/**
* Returns the percentage in the closed interval `[0, 1]` of the given value
* between the start and end point.
*
* @param {number} x - The start point
* @param {number} y - The end point.
* @param {number} value - A value between start and end.
* @return {number} The interpolation factor.
*/
function inverseLerp( x, y, value ) {
// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
if ( x !== y ) {
return ( value - x ) / ( y - x );
} else {
return 0;
}
}
/**
* Returns a value linearly interpolated from two known points based on the given interval -
* `t = 0` will return `x` and `t = 1` will return `y`.
*
* @param {number} x - The start point
* @param {number} y - The end point.
* @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
* @return {number} The interpolated value.
*/
function lerp$1( x, y, t ) {
return ( 1 - t ) * x + t * y;
}
/**
* Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta
* time to maintain frame rate independent movement. For details, see
* [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}.
*
* @param {number} x - The current point.
* @param {number} y - The target point.
* @param {number} lambda - A higher lambda value will make the movement more sudden,
* and a lower value will make the movement more gradual.
* @param {number} dt - Delta time in seconds.
* @return {number} The interpolated value.
*/
function damp( x, y, lambda, dt ) {
return lerp$1( x, y, 1 - Math.exp( - lambda * dt ) );
}
/**
* Returns a value that alternates between `0` and the given `length` parameter.
*
* @param {number} x - The value to pingpong.
* @param {number} [length=1] - The positive value the function will pingpong to.
* @return {number} The alternated value.
*/
function pingpong( x, length = 1 ) {
// https://www.desmos.com/calculator/vcsjnyz7x4
return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
}
/**
* Returns a value in the range `[0,1]` that represents the percentage that `x` has
* moved between `min` and `max`, but smoothed or slowed down the closer `x` is to
* the `min` and `max`.
*
* See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details.
*
* @param {number} x - The value to evaluate based on its position between min and max.
* @param {number} min - The min value. Any x value below min will be `0`.
* @param {number} max - The max value. Any x value above max will be `1`.
* @return {number} The alternated value.
*/
function smoothstep( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * ( 3 - 2 * x );
}
/**
* A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations}
* that has zero 1st and 2nd order derivatives at x=0 and x=1.
*
* @param {number} x - The value to evaluate based on its position between min and max.
* @param {number} min - The min value. Any x value below min will be `0`.
* @param {number} max - The max value. Any x value above max will be `1`.
* @return {number} The alternated value.
*/
function smootherstep( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
}
/**
* Returns a random integer from `<low, high>` interval.
*
* @param {number} low - The lower value boundary.
* @param {number} high - The upper value boundary
* @return {number} A random integer.
*/
function randInt( low, high ) {
return low + Math.floor( Math.random() * ( high - low + 1 ) );
}
/**
* Returns a random float from `<low, high>` interval.
*
* @param {number} low - The lower value boundary.
* @param {number} high - The upper value boundary
* @return {number} A random float.
*/
function randFloat( low, high ) {
return low + Math.random() * ( high - low );
}
/**
* Returns a random integer from `<-range/2, range/2>` interval.
*
* @param {number} range - Defines the value range.
* @return {number} A random float.
*/
function randFloatSpread( range ) {
return range * ( 0.5 - Math.random() );
}
/**
* Returns a deterministic pseudo-random float in the interval `[0, 1]`.
*
* @param {number} [s] - The integer seed.
* @return {number} A random float.
*/
function seededRandom( s ) {
if ( s !== undefined ) _seed = s;
// Mulberry32 generator
let t = _seed += 0x6D2B79F5;
t = Math.imul( t ^ t >>> 15, t | 1 );
t ^= t + Math.imul( t ^ t >>> 7, t | 61 );
return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;
}
/**
* Converts degrees to radians.
*
* @param {number} degrees - A value in degrees.
* @return {number} The converted value in radians.
*/
function degToRad( degrees ) {
return degrees * DEG2RAD;
}
/**
* Converts radians to degrees.
*
* @param {number} radians - A value in radians.
* @return {number} The converted value in degrees.
*/
function radToDeg( radians ) {
return radians * RAD2DEG;
}
/**
* Returns `true` if the given number is a power of two.
*
* @param {number} value - The value to check.
* @return {boolean} Whether the given number is a power of two or not.
*/
function isPowerOfTwo( value ) {
return ( value & ( value - 1 ) ) === 0 && value !== 0;
}
/**
* Returns the smallest power of two that is greater than or equal to the given number.
*
* @param {number} value - The value to find a POT for.
* @return {number} The smallest power of two that is greater than or equal to the given number.
*/
function ceilPowerOfTwo( value ) {
return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
}
/**
* Returns the largest power of two that is less than or equal to the given number.
*
* @param {number} value - The value to find a POT for.
* @return {number} The largest power of two that is less than or equal to the given number.
*/
function floorPowerOfTwo( value ) {
return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
}
/**
* Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles}
* defined by the given angles and order.
*
* Rotations are applied to the axes in the order specified by order:
* rotation by angle `a` is applied first, then by angle `b`, then by angle `c`.
*
* @param {Quaternion} q - The quaternion to set.
* @param {number} a - The rotation applied to the first axis, in radians.
* @param {number} b - The rotation applied to the second axis, in radians.
* @param {number} c - The rotation applied to the third axis, in radians.
* @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order.
*/
function setQuaternionFromProperEuler( q, a, b, c, order ) {
const cos = Math.cos;
const sin = Math.sin;
const c2 = cos( b / 2 );
const s2 = sin( b / 2 );
const c13 = cos( ( a + c ) / 2 );
const s13 = sin( ( a + c ) / 2 );
const c1_3 = cos( ( a - c ) / 2 );
const s1_3 = sin( ( a - c ) / 2 );
const c3_1 = cos( ( c - a ) / 2 );
const s3_1 = sin( ( c - a ) / 2 );
switch ( order ) {
case 'XYX':
q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
break;
case 'YZY':
q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
break;
case 'ZXZ':
q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
break;
case 'XZX':
q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
break;
case 'YXY':
q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
break;
case 'ZYZ':
q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
break;
default:
console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
}
}
/**
* Denormalizes the given value according to the given typed array.
*
* @param {number} value - The value to denormalize.
* @param {TypedArray} array - The typed array that defines the data type of the value.
* @return {number} The denormalize (float) value in the range `[0,1]`.
*/
function denormalize( value, array ) {
switch ( array.constructor ) {
case Float32Array:
return value;
case Uint32Array:
return value / 4294967295.0;
case Uint16Array:
return value / 65535.0;
case Uint8Array:
return value / 255.0;
case Int32Array:
return Math.max( value / 2147483647.0, -1 );
case Int16Array:
return Math.max( value / 32767.0, -1 );
case Int8Array:
return Math.max( value / 127.0, -1 );
default:
throw new Error( 'Invalid component type.' );
}
}
/**
* Normalizes the given value according to the given typed array.
*
* @param {number} value - The float value in the range `[0,1]` to normalize.
* @param {TypedArray} array - The typed array that defines the data type of the value.
* @return {number} The normalize value.
*/
function normalize( value, array ) {
switch ( array.constructor ) {
case Float32Array:
return value;
case Uint32Array:
return Math.round( value * 4294967295.0 );
case Uint16Array:
return Math.round( value * 65535.0 );
case Uint8Array:
return Math.round( value * 255.0 );
case Int32Array:
return Math.round( value * 2147483647.0 );
case Int16Array:
return Math.round( value * 32767.0 );
case Int8Array:
return Math.round( value * 127.0 );
default:
throw new Error( 'Invalid component type.' );
}
}
const MathUtils = {
DEG2RAD: DEG2RAD,
RAD2DEG: RAD2DEG,
generateUUID: generateUUID,
clamp: clamp$1,
euclideanModulo: euclideanModulo,
mapLinear: mapLinear,
inverseLerp: inverseLerp,
lerp: lerp$1,
damp: damp,
pingpong: pingpong,
smoothstep: smoothstep,
smootherstep: smootherstep,
randInt: randInt,
randFloat: randFloat,
randFloatSpread: randFloatSpread,
seededRandom: seededRandom,
degToRad: degToRad,
radToDeg: radToDeg,
isPowerOfTwo: isPowerOfTwo,
ceilPowerOfTwo: ceilPowerOfTwo,
floorPowerOfTwo: floorPowerOfTwo,
setQuaternionFromProperEuler: setQuaternionFromProperEuler,
normalize: normalize,
denormalize: denormalize
};
/**
* Class representing a 2D vector. A 2D vector is an ordered pair of numbers
* (labeled x and y), which can be used to represent a number of things, such as:
*
* - A point in 2D space (i.e. a position on a plane).
* - A direction and length across a plane. In three.js the length will
* always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)`
* and the direction is also measured from `(0, 0)` towards `(x, y)`.
* - Any arbitrary ordered pair of numbers.
*
* There are other things a 2D vector can be used to represent, such as
* momentum vectors, complex numbers and so on, however these are the most
* common uses in three.js.
*
* Iterating through a vector instance will yield its components `(x, y)` in
* the corresponding order.
* ```js
* const a = new THREE.Vector2( 0, 1 );
*
* //no arguments; will be initialised to (0, 0)
* const b = new THREE.Vector2( );
*
* const d = a.distanceTo( b );
* ```
*/
class Vector2 {
/**
* Constructs a new 2D vector.
*
* @param {number} [x=0] - The x value of this vector.
* @param {number} [y=0] - The y value of this vector.
*/
constructor( x = 0, y = 0 ) {
/**
* This flag can be used for type testing.
*
* @type {boolean}
* @readonly
* @default true
*/
Vector2.prototype.isVector2 = true;
/**
* The x value of this vector.
*
* @type {number}
*/
this.x = x;
/**
* The y value of this vector.
*
* @type {number}
*/
this.y = y;
}
/**
* Alias for {@link Vector2#x}.
*
* @type {number}
*/
get width() {
return this.x;
}
set width( value ) {
this.x = value;
}
/**
* Alias for {@link Vector2#y}.
*
* @type {number}
*/
get height() {
return this.y;
}
set height( value ) {
this.y = value;
}
/**
* Sets the vector components.
*
* @param {number} x - The value of the x component.
* @param {number} y - The value of the y component.
* @return {Vector2} A reference to this vector.
*/
set( x, y ) {
this.x = x;
this.y = y;
return this;
}
/**
* Sets the vector components to the same value.
*
* @param {number} scalar - The value to set for all vector components.
* @return {Vector2} A reference to this vector.
*/
setScalar( scalar ) {
this.x = scalar;
this.y = scalar;
return this;
}
/**
* Sets the vector's x component to the given value
*
* @param {number} x - The value to set.
* @return {Vector2} A reference to this vector.
*/
setX( x ) {
this.x = x;
return this;
}
/**
* Sets the vector's y component to the given value
*
* @param {number} y - The value to set.
* @return {Vector2} A reference to this vector.
*/
setY( y ) {
this.y = y;
return this;
}
/**
* Allows to set a vector component with an index.
*
* @param {number} index - The component index. `0` equals to x, `1` equals to y.
* @param {number} value - The value to set.
* @return {Vector2} A reference to this vector.
*/
setComponent( index, value ) {
switch ( index ) {
case 0: this.x = value; break;
case 1: this.y = value; break;
default: throw new Error( 'index is out of range: ' + index );
}
return this;
}
/**
* Returns the value of the vector component which matches the given index.
*
* @param {number} index - The component index. `0` equals to x, `1` equals to y.
* @return {number} A vector component value.
*/
getComponent( index ) {
switch ( index ) {
case 0: return this.x;
case 1: return this.y;
default: throw new Error( 'index is out of range: ' + index );
}
}
/**
* Returns a new vector with copied values from this instance.
*
* @return {Vector2} A clone of this instance.
*/
clone() {
return new this.constructor( this.x, this.y );
}
/**
* Copies the values of the given vector to this instance.
*
* @param {Vector2} v - The vector to copy.
* @return {Vector2} A reference to this vector.
*/
copy( v ) {
this.x = v.x;
this.y = v.y;
return this;
}
/**
* Adds the given vector to this instance.
*
* @param {Vector2} v - The vector to add.
* @return {Vector2} A reference to this vector.
*/
add( v ) {
this.x += v.x;
this.y += v.y;
return this;
}
/**
* Adds the given scalar value to all components of this instance.
*
* @param {number} s - The scalar to add.
* @return {Vector2} A reference to this vector.
*/
addScalar( s ) {
this.x += s;
this.y += s;
return this;
}
/**
* Adds the given vectors and stores the result in this instance.
*
* @param {Vector2} a - The first vector.
* @param {Vector2} b - The second vector.
* @return {Vector2} A reference to this vector.
*/
addVectors( a, b ) {
this.x = a.x + b.x;
this.y = a.y + b.y;
return this;
}
/**
* Adds the given vector scaled by the given factor to this instance.
*
* @param {Vector2} v - The vector.
* @param {number} s - The factor that scales `v`.
* @return {Vector2} A reference to this vector.
*/
addScaledVector( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
return this;
}
/**
* Subtracts the given vector from this instance.
*
* @param {Vector2} v - The vector to subtract.
* @return {Vector2} A reference to this vector.
*/
sub( v ) {
this.x -= v.x;
this.y -= v.y;
return this;
}
/**
* Subtracts the given scalar value from all components of this instance.
*
* @param {number} s - The scalar to subtract.
* @return {Vector2} A reference to this vector.
*/
subScalar( s ) {
this.x -= s;
this.y -= s;
return this;
}
/**
* Subtracts the given vectors and stores the result in this instance.
*
* @param {Vector2} a - The first vector.
* @param {Vector2} b - The second vector.
* @return {Vector2} A reference to this vector.
*/
subVectors( a, b ) {
this.x = a.x - b.x;
this.y = a.y - b.y;
return this;
}
/**
* Multiplies the given vector with this instance.
*
* @param {Vector2} v - The vector to multiply.
* @return {Vector2} A reference to this vector.
*/
multiply( v ) {
this.x *= v.x;
this.y *= v.y;
return this;
}
/**
* Multiplies the given scalar value with all components of this instance.
*
* @param {number} scalar - The scalar to multiply.
* @return {Vector2} A reference to this vector.
*/
multiplyScalar( scalar ) {
this.x *= scalar;
this.y *= scalar;
return this;
}
/**
* Divides this instance by the given vector.
*
* @param {Vector2} v - The vector to divide.
* @return {Vector2} A reference to this vector.
*/
divide( v ) {
this.x /= v.x;
this.y /= v.y;
return this;
}
/**
* Divides this vector by the given scalar.
*
* @param {number} scalar - The scalar to divide.
* @return {Vector2} A reference to this vector.
*/
divideScalar( scalar ) {
return this.multiplyScalar( 1 / scalar );
}
/**
* Multiplies this vector (with an implicit 1 as the 3rd component) by
* the given 3x3 matrix.
*
* @param {Matrix3} m - The matrix to apply.
* @return {Vector2} A reference to this vector.
*/
applyMatrix3( m ) {
const x = this.x, y = this.y;
const e = m.elements;
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
return this;
}
/**
* If this vector's x or y value is greater than the given vector's x or y
* value, replace that value with the corresponding min value.
*
* @param {Vector2} v - The vector.
* @return {Vector2} A reference to this vector.
*/
min( v ) {
this.x = Math.min( this.x, v.x );
this.y = Math.min( this.y, v.y );
return this;
}
/**
* If this vector's x or y value is less than the given vector's x or y
* value, replace that value with the corresponding max value.
*
* @param {Vector2} v - The vector.
* @return {Vector2} A reference to this vector.
*/
max( v ) {
this.x = Math.max( this.x, v.x );
this.y = Math.max( this.y, v.y );
return this;
}
/**
* If this vector's x or y value is greater than the max vector's x or y
* value, it is replaced by the corresponding value.
* If this vector's x or y value is less than the min vector's x or y value,
* it is replaced by the corresponding value.
*
* @param {Vector2} min - The minimum x and y values.
* @param {Vector2} max - The maximum x and y values in the desired range.
* @return {Vector2} A reference to this vector.
*/
clamp( min, max ) {
// assumes min < max, componentwise
this.x = clamp$1( this.x, min.x, max.x );
this.y = clamp$1( this.y, min.y, max.y );
return this;
}
/**
* If this vector's x or y values are greater than the max value, they are
* replaced by the max value.
* If this vector's x or y values are less than the min value, they are
* replaced by the min value.
*
* @param {number} minVal - The minimum value the components will be clamped to.
* @param {number} maxVal - The maximum value the components will be clamped to.
* @return {Vector2} A reference to this vector.
*/
clampScalar( minVal, maxVal ) {
this.x = clamp$1( this.x, minVal, maxVal );
this.y = clamp$1( this.y, minVal, maxVal );
return this;
}
/**
* If this vector's length is greater than the max value, it is replaced by
* the max value.
* If this vector's length is less than the min value, it is replaced by the
* min value.
*
* @param {number} min - The minimum value the vector length will be clamped to.
* @param {number} max - The maximum value the vector length will be clamped to.
* @return {Vector2} A reference to this vector.
*/
clampLength( min, max ) {
const length = this.length();
return this.divideScalar( length || 1 ).multiplyScalar( clamp$1( length, min, max ) );
}
/**
* The components of this vector are rounded down to the nearest integer value.
*
* @return {Vector2} A reference to this vector.
*/
floor() {
this.x = Math.floor( this.x );
this.y = Math.floor( this.y );
return this;
}
/**
* The components of this vector are rounded up to the nearest integer value.
*
* @return {Vector2} A reference to this vector.
*/
ceil() {
this.x = Math.ceil( this.x );
this.y = Math.ceil( this.y );
return this;
}
/**
* The components of this vector are rounded to the nearest integer value
*
* @return {Vector2} A reference to this vector.
*/
round() {
this.x = Math.round( this.x );
this.y = Math.round( this.y );
return this;
}
/**
* The components of this vector are rounded towards zero (up if negative,
* down if positive) to an integer value.
*
* @return {Vector2} A reference to this vector.
*/
roundToZero() {
this.x = Math.trunc( this.x );
this.y = Math.trunc( this.y );
return this;
}
/**
* Inverts this vector - i.e. sets x = -x and y = -y.
*
* @return {Vector2} A reference to this vector.
*/
negate() {
this.x = - this.x;
this.y = - this.y;
return this;
}
/**
* Calculates the dot product of the given vector with this instance.
*
* @param {Vector2} v - The vector to compute the dot product with.
* @return {number} The result of the dot product.
*/
dot( v ) {
return this.x * v.x + this.y * v.y;
}
/**
* Calculates the cross product of the given vector with this instance.
*
* @param {Vector2} v - The vector to compute the cross product with.
* @return {number} The result of the cross product.
*/
cross( v ) {
return this.x * v.y - this.y * v.x;
}
/**
* Computes the square of the Euclidean length (straight-line length) from
* (0, 0) to (x, y). If you are comparing the lengths of vectors, you should
* compare the length squared instead as it is slightly more efficient to calculate.
*
* @return {number} The square length of this vector.
*/
lengthSq() {
return this.x * this.x + this.y * this.y;
}
/**
* Computes the Euclidean length (straight-line length) from (0, 0) to (x, y).
*
* @return {number} The length of this vector.
*/
length() {
return Math.sqrt( this.x * this.x + this.y * this.y );
}
/**
* Computes the Manhattan length of this vector.
*
* @return {number} The length of this vector.
*/
manhattanLength() {
return Math.abs( this.x ) + Math.abs( this.y );
}
/**
* Converts this vector to a unit vector - that is, sets it equal to a vector
* with the same direction as this one, but with a vector length of `1`.
*
* @return {Vector2} A reference to this vector.
*/
normalize() {
return this.divideScalar( this.length() || 1 );
}
/**
* Computes the angle in radians of this vector with respect to the positive x-axis.
*
* @return {number} The angle in radians.
*/
angle() {
const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
return angle;
}
/**
* Returns the angle between the given vector and this instance in radians.
*
* @param {Vector2} v - The vector to compute the angle with.
* @return {number} The angle in radians.
*/
angleTo( v ) {
const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
if ( denominator === 0 ) return Math.PI / 2;
const theta = this.dot( v ) / denominator;
// clamp, to handle numerical problems
return Math.acos( clamp$1( theta, -1, 1 ) );
}
/**
* Computes the distance from the given vector to this instance.
*
* @param {Vector2} v - The vector to compute the distance to.
* @return {number} The distance.
*/
distanceTo( v ) {
return Math.sqrt( this.distanceToSquared( v ) );
}
/**
* Computes the squared distance from the given vector to this instance.
* If you are just comparing the distance with another distance, you should compare
* the distance squared instead as it is slightly more efficient to calculate.
*
* @param {Vector2} v - The vector to compute the squared distance to.
* @return {number} The squared distance.
*/
distanceToSquared( v ) {
const dx = this.x - v.x, dy = this.y - v.y;
return dx * dx + dy * dy;
}
/**
* Computes the Manhattan distance from the given vector to this instance.
*
* @param {Vector2} v - The vector to compute the Manhattan distance to.
* @return {number} The Manhattan distance.
*/
manhattanDistanceTo( v ) {
return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
}
/**
* Sets this vector to a vector with the same direction as this one, but
* with the specified length.
*
* @param {number} length - The new length of this vector.
* @return {Vector2} A reference to this vector.
*/
setLength( length ) {
return this.normalize().multiplyScalar( length );
}
/**
* Linearly interpolates between the given vector and this instance, where
* alpha is the percent distance along the line - alpha = 0 will be this
* vector, and alpha = 1 will be the given one.
*
* @param {Vector2} v - The vector to interpolate towards.
* @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
* @return {Vector2} A reference to this vector.
*/
lerp( v, alpha ) {
this.x += ( v.x - this.x ) * alpha;
this.y += ( v.y - this.y ) * alpha;
return this;
}
/**
* Linearly interpolates between the given vectors, where alpha is the percent
* distance along the line - alpha = 0 will be first vector, and alpha = 1 will
* be the second one. The result is stored in this instance.
*
* @param {Vector2} v1 - The first vector.
* @param {Vector2} v2 - The second vector.
* @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
* @return {Vector2} A reference to this vector.
*/
lerpVectors( v1, v2, alpha ) {
this.x = v1.x + ( v2.x - v1.x ) * alpha;
this.y = v1.y + ( v2.y - v1.y ) * alpha;
return this;
}
/**
* Returns `true` if this vector is equal with the given one.
*
* @param {Vector2} v - The vector to test for equality.
* @return {boolean} Whether this vector is equal with the given one.
*/
equals( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) );
}
/**
* Sets this vector's x value to be `array[ offset ]` and y
* value to be `array[ offset + 1 ]`.
*
* @param {Array<number>} array - An array holding the vector component values.
* @param {number} [offset=0] - The offset into the array.
* @return {Vector2} A reference to this vector.
*/
fromArray( array, offset = 0 ) {
this.x = array[ offset ];
this.y = array[ offset + 1 ];
return this;
}
/**
* Writes the components of this vector to the given array. If no array is provided,
* the method returns a new instance.
*
* @param {Array<number>} [array=[]] - The target array holding the vector components.
* @param {number} [offset=0] - Index of the first element in the array.
* @return {Array<number>} The vector components.
*/
toArray( array = [], offset = 0 ) {
array[ offset ] = this.x;
array[ offset + 1 ] = this.y;
return array;
}
/**
* Sets the components of this vector from the given buffer attribute.
*
* @param {BufferAttribute} attribute - The buffer attribute holding vector data.
* @param {number} index - The index into the attribute.
* @return {Vector2} A reference to this vector.
*/
fromBufferAttribute( attribute, index ) {
this.x = attribute.getX( index );
this.y = attribute.getY( index );
return this;
}
/**
* Rotates this vector around the given center by the given angle.
*
* @param {Vector2} center - The point around which to rotate.
* @param {number} angle - The angle to rotate, in radians.
* @return {Vector2} A reference to this vector.
*/
rotateAround( center, angle ) {
const c = Math.cos( angle ), s = Math.sin( angle );
const x = this.x - center.x;
const y = this.y - center.y;
this.x = x * c - y * s + center.x;
this.y = x * s + y * c + center.y;
return this;
}
/**
* Sets each component of this vector to a pseudo-random value between `0` and
* `1`, excluding `1`.
*
* @return {Vector2} A reference to this vector.
*/
random() {
this.x = Math.random();
this.y = Math.random();
return this;
}
*[ Symbol.iterator ]() {
yield this.x;
yield this.y;
}
}
/**
* Represents a 3x3 matrix.
*
* A Note on Row-Major and Column-Major Ordering:
*
* The constructor and {@link Matrix3#set} method take arguments in
* [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order}
* order, while internally they are stored in the {@link Matrix3#elements} array in column-major order.
* This means that calling:
* ```js
* const m = new THREE.Matrix();
* m.set( 11, 12, 13,
* 21, 22, 23,
* 31, 32, 33 );
* ```
* will result in the elements array containing:
* ```js
* m.elements = [ 11, 21, 31,
* 12, 22, 32,
* 13, 23, 33 ];
* ```
* and internally all calculations are performed using column-major ordering.
* However, as the actual ordering makes no difference mathematically and
* most people are used to thinking about matrices in row-major order, the
* three.js documentation shows matrices in row-major order. Just bear in
* mind that if you are reading the source code, you'll have to take the
* transpose of any matrices outlined here to make sense of the calculations.
*/
class Matrix3 {
/**
* Constructs a new 3x3 matrix. The arguments are supposed to be
* in row-major order. If no arguments are provided, the constructor
* initializes the matrix as an identity matrix.
*
* @param {number} [n11] - 1-1 matrix element.
* @param {number} [n12] - 1-2 matrix element.
* @param {number} [n13] - 1-3 matrix element.
* @param {number} [n21] - 2-1 matrix element.
* @param {number} [n22] - 2-2 matrix element.
* @param {number} [n23] - 2-3 matrix element.
* @param {number} [n31] - 3-1 matrix element.
* @param {number} [n32] - 3-2 matrix element.
* @param {number} [n33] - 3-3 matrix element.
*/
constructor(