UNPKG

@ccp-nc/crystvis-js

Version:

A Three.js based crystallographic visualisation tool

221 lines (181 loc) 6.34 kB
'use strict'; import _ from 'lodash'; import * as mjs from 'mathjs'; import * as THREE from 'three'; import { unitSphere, } from './geometries.js'; import { DitherMaterial } from './dither.js'; import { addStaticVar } from '../utils.js'; // Basic materials const _phong = new THREE.MeshPhongMaterial({}); class EllipsoidMesh extends THREE.Mesh { constructor(parameters = {}) { const defaults = { center: [0, 0, 0], eigenvalues: [1, 1, 1], eigenvectors: [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ], color: 0xff0000, opacity: 0.5, opacityMode: EllipsoidMesh.DITHER, showEllipsoid: true, showCircles: true, showAxes: true, scalingFactor: 1.0 }; parameters = _.merge(defaults, parameters); var geometry = unitSphere; var material; var c = new THREE.Color(parameters.color); switch (parameters.opacityMode) { case EllipsoidMesh.DITHER: material = new DitherMaterial({ color: c, opacity: parameters.opacity, shiftSeed: parameters.ditherSeed }); break; case EllipsoidMesh.PHONG: material = new THREE.MeshPhongMaterial({ transparent: true, color: c, opacity: parameters.opacity }); break; default: throw new Error('Invalid opacityMode argument passed to EllipsoidMesh'); } super(geometry, material); if (parameters.showCircles) { let matline = new THREE.LineBasicMaterial({ color: new THREE.Color(c), }); let geoline = new THREE.CircleGeometry(1.0, 32); geoline = new THREE.EdgesGeometry(geoline); let cseg = new THREE.LineSegments(geoline, matline); this.add(cseg); cseg = new THREE.LineSegments(geoline, matline); cseg.rotateX(Math.PI / 2.0); this.add(cseg); cseg = new THREE.LineSegments(geoline, matline); cseg.rotateY(Math.PI / 2.0); this.add(cseg); } if (parameters.showAxes) { let matline = new THREE.LineBasicMaterial({ color: new THREE.Color(0xff0000), }); let geoline = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(-1, 0, 0), new THREE.Vector3(1, 0, 0) ]); // change the color of the x axis matline = new THREE.LineBasicMaterial({ color: new THREE.Color(0xff0000), }); let xseg = new THREE.LineSegments(geoline, matline); this.add(xseg); // change the color of the y axis matline = new THREE.LineBasicMaterial({ color: new THREE.Color(0x00ff00), }); let yseg = new THREE.LineSegments(geoline, matline); yseg.rotateZ(Math.PI / 2.0); this.add(yseg); // change the color of the z axis matline = new THREE.LineBasicMaterial({ color: new THREE.Color(0x0000ff), }); // matline.color = new THREE.Color(0x0000ff); let zseg = new THREE.LineSegments(geoline, matline); zseg.rotateY(Math.PI / 2.0); this.add(zseg); } let c0 = parameters.center; if (!(c0 instanceof THREE.Vector3)) { c0 = new THREE.Vector3(c0[0], c0[1], c0[2]); } this.position.copy(c0); this._scalefactor = parameters.scalingFactor; this.eigenvalues = parameters.eigenvalues; this.eigenvectors = parameters.eigenvectors; // set material to be invisible if showEllipsoid is false if (!parameters.showEllipsoid) { material.visible = false; } this.renderOrder = 0.5; } get eigenvalues() { return Array.from(this._eigenvalues); } set eigenvalues(v) { this._eigenvalues = v; this.scalingFactor = this._scalefactor; } get eigenvectors() { return JSON.parse(JSON.stringify(this._eigenvectors)); } set eigenvectors(v) { this._eigenvectors = v; var basis = _.map(_.range(3), (i) => { return new THREE.Vector3(v[0][i], v[1][i], v[2][i]).normalize(); }); var rotm = new THREE.Matrix4(); rotm.makeBasis(basis[0], basis[1], basis[2]); this.setRotationFromMatrix(rotm); } get color() { // Handle both standard materials and DitherMaterial if (this.material.uniforms && this.material.uniforms.color) { return this.material.uniforms.color.value.getHex(); } else if (this.material.color) { return this.material.color.getHex(); } return 0xffffff; // Default fallback } set color(c) { // Change all colors const color = new THREE.Color(c); // Handle DitherMaterial or standard material if (this.material.uniforms && this.material.uniforms.color) { this.material.uniforms.color.value.set(c); this.material.uniformsNeedUpdate = true; } else if (this.material.color) { this.material.color.set(c); } // Update child elements for (let i = 0; i < this.children.length; ++i) { const childMaterial = this.children[i].material; if (childMaterial && childMaterial.color) { childMaterial.color.set(c); } } } get opacity() { return this.material.opacity; } set opacity(o) { this.material.opacity = o; } get scalingFactor() { return this._scalefactor; } set scalingFactor(s) { this._scalefactor = s; this.scale.fromArray(mjs.multiply(this._eigenvalues, s)); } } addStaticVar(EllipsoidMesh, 'DITHER', 0); addStaticVar(EllipsoidMesh, 'PHONG', 1); export { EllipsoidMesh }