constructor( xLength, yLength, zLength, type, arrayBuffer ) {

		if ( xLength !== undefined ) {

			/**
			 * Width of the volume in the IJK coordinate system.
			 *
			 * @type {number}
			 * @default 1
			 */
			this.xLength = Number( xLength ) || 1;

			/**
			 * Height of the volume in the IJK coordinate system.
			 *
			 * @type {number}
			 * @default 1
			 */
			this.yLength = Number( yLength ) || 1;

			/**
			 * Depth of the volume in the IJK coordinate system.
			 *
			 * @type {number}
			 * @default 1
			 */
			this.zLength = Number( zLength ) || 1;

			/**
			 * The order of the Axis dictated by the NRRD header
			 *
			 * @type {Array<string>}
			 */
			this.axisOrder = [ 'x', 'y', 'z' ];

			/**
			 * The data of the volume.
			 *
			 * @type {TypedArray}
			 */
			this.data;

			switch ( type ) {

				case 'Uint8' :
				case 'uint8' :
				case 'uchar' :
				case 'unsigned char' :
				case 'uint8_t' :
					this.data = new Uint8Array( arrayBuffer );
					break;
				case 'Int8' :
				case 'int8' :
				case 'signed char' :
				case 'int8_t' :
					this.data = new Int8Array( arrayBuffer );
					break;
				case 'Int16' :
				case 'int16' :
				case 'short' :
				case 'short int' :
				case 'signed short' :
				case 'signed short int' :
				case 'int16_t' :
					this.data = new Int16Array( arrayBuffer );
					break;
				case 'Uint16' :
				case 'uint16' :
				case 'ushort' :
				case 'unsigned short' :
				case 'unsigned short int' :
				case 'uint16_t' :
					this.data = new Uint16Array( arrayBuffer );
					break;
				case 'Int32' :
				case 'int32' :
				case 'int' :
				case 'signed int' :
				case 'int32_t' :
					this.data = new Int32Array( arrayBuffer );
					break;
				case 'Uint32' :
				case 'uint32' :
				case 'uint' :
				case 'unsigned int' :
				case 'uint32_t' :
					this.data = new Uint32Array( arrayBuffer );
					break;
				case 'longlong' :
				case 'long long' :
				case 'long long int' :
				case 'signed long long' :
				case 'signed long long int' :
				case 'int64' :
				case 'int64_t' :
				case 'ulonglong' :
				case 'unsigned long long' :
				case 'unsigned long long int' :
				case 'uint64' :
				case 'uint64_t' :
					throw new Error( 'Error in Volume constructor : this type is not supported in JavaScript' );
					break;
				case 'Float32' :
				case 'float32' :
				case 'float' :
					this.data = new Float32Array( arrayBuffer );
					break;
				case 'Float64' :
				case 'float64' :
				case 'double' :
					this.data = new Float64Array( arrayBuffer );
					break;
				default :
					this.data = new Uint8Array( arrayBuffer );

			}

			if ( this.data.length !== this.xLength * this.yLength * this.zLength ) {

				throw new Error( 'Error in Volume constructor, lengths are not matching arrayBuffer size' );

			}

		}

		/**
		 * Spacing to apply to the volume from IJK to RAS coordinate system
		 *
		 * @type {Array<number>}
		 */
		this.spacing = [ 1, 1, 1 ];

		/**
		 * Offset of the volume in the RAS coordinate system
		 *
		 * @type {Array<number>}
		 */
		this.offset = [ 0, 0, 0 ];

		/**
		 * The IJK to RAS matrix.
		 *
		 * @type {Martrix3}
		 */
		this.matrix = new Matrix3();
		this.matrix.identity();

		/**
		 * The RAS to IJK matrix.
		 *
		 * @type {Martrix3}
		 */
		this.inverseMatrix = new Matrix3();

		let lowerThreshold = - Infinity;
		Object.defineProperty( this, 'lowerThreshold', {
			get: function () {

				return lowerThreshold;

			},
			/**
			 * The voxels with values under this threshold won't appear in the slices.
			 * If changed, geometryNeedsUpdate is automatically set to true on all the slices associated to this volume.
			 *
			 * @name Volume#lowerThreshold
			 * @type {number}
			 * @param {number} value
			 */
			set: function ( value ) {

				lowerThreshold = value;
				this.sliceList.forEach( function ( slice ) {

					slice.geometryNeedsUpdate = true;

				} );

			}
		} );

		let upperThreshold = Infinity;
		Object.defineProperty( this, 'upperThreshold', {
			get: function () {

				return upperThreshold;

			},
			/**
			 * The voxels with values over this threshold won't appear in the slices.
			 * If changed, geometryNeedsUpdate is automatically set to true on all the slices associated to this volume
			 *
			 * @name Volume#upperThreshold
			 * @type {number}
			 * @param {number} value
			 */
			set: function ( value ) {

				upperThreshold = value;
				this.sliceList.forEach( function ( slice ) {

					slice.geometryNeedsUpdate = true;

				} );

			}
		} );


		/**
		 * The list of all the slices associated to this volume
		 *
		 * @type {Array}
		 */
		this.sliceList = [];

		/**
		 * Whether to use segmentation mode or not.
		 * It can load 16-bits nrrds correctly.
		 *
		 * @type {boolean}
		 * @default false
		 */
		this.segmentation = false;


		/**
		 * This array holds the dimensions of the volume in the RAS space
		 *
		 * @type {Array<number>}
		 */
		this.RASDimensions = [];

	}
Constructs a new volume.

@param {number} [xLength] - Width of the volume.
@param {number} [yLength] - Length of the volume.
@param {number} [zLength] - Depth of the volume.
@param {string} [type] - The type of data (uint8, uint16, ...).
@param {ArrayBuffer} [arrayBuffer] - The buffer with volume data.