Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix currentFrame, viewRect in transform #1

Merged
merged 2 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ npm run build
npx playwright test
```

Run the test with the title

```
npx playwright test -g "Animation"
```

If the snapshots need to be updated:

```
Expand Down
2 changes: 2 additions & 0 deletions demo/demo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { WEAS, Atoms, Species, parseXYZ, parseCIF, parseCube } from "../src/index.js"; // Adjust the path as necessary
import * as THREE from "three";

window.THREE = THREE;
window.WEAS = WEAS;
window.Atoms = Atoms;
window.Species = Species;
Expand Down
1 change: 1 addition & 0 deletions examples/h2o.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://unpkg.com/weas/dist/style.css" />
<title>WEAS Molecule</title>
</head>
<body>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "weas",
"version": "0.1.0",
"version": "0.1.1",
"description": "WEAS (Web Environment for Atomic Structures) is a JavaScript library to visualize and manipulate the atomistic structures directly in the web browser",
"main": "src/index.js",
"scripts": {
Expand Down
30 changes: 25 additions & 5 deletions src/atoms/AtomsViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,10 @@ class AtomsViewer {
}
this.atomColors = getAtomColors(this.atoms, this.colorBy, { colorType: this.colorType, colorRamp: this._colorRamp });
this.drawBalls();
this.bondManager.drawBonds();
this.polyhedraManager.drawPolyhedras();
const bondMesh = this.bondManager.drawBonds();
this.atomsMesh.add(bondMesh);
const polyhedraMesh = this.polyhedraManager.drawPolyhedras();
this.atomsMesh.add(polyhedraMesh);
this.isosurfaceManager.drawIsosurfaces();
if (this.showVectorField) {
this.VFManager.drawVectorFields();
Expand All @@ -459,6 +461,7 @@ class AtomsViewer {
drawBalls() {
// draw atoms
this.atomsMesh = drawAtoms({ scene: this.tjs.scene, atoms: this.atoms, atomScales: this.atomScales, colors: this.atomColors, radiusType: this.radiusType, materialType: this._materialType });
this.tjs.scene.add(this.atomsMesh);
// atoms to be drawn, boundary atoms, and the bonded atoms
// merge the boundaryList and the bondedAtoms
this.imageAtomsList = this.bondedAtoms["atoms"].concat(this.boundaryList);
Expand All @@ -473,7 +476,16 @@ class AtomsViewer {
atomScales[i] = this.atomScales[this.imageAtomsList[i][0]];
}
const atomColors = getAtomColors(imageAtomsList, this.colorBy, { colorType: this.colorType, defaultColor: "#0xffffff", colorRamp: this._colorRamp });
this.boundaryAtomsMesh = drawAtoms({ scene: this.tjs.scene, atoms: imageAtomsList, atomScales: atomScales, colors: atomColors, radiusType: this.radiusType, materialType: this._materialType });
this.boundaryAtomsMesh = drawAtoms({
scene: this.tjs.scene,
atoms: imageAtomsList,
atomScales: atomScales,
colors: atomColors,
radiusType: this.radiusType,
materialType: this._materialType,
data_type: "boundary",
});
this.atomsMesh.add(this.boundaryAtomsMesh);
}
}

Expand All @@ -482,8 +494,16 @@ class AtomsViewer {
const atomScales = new Array(this.atoms.getAtomsCount()).fill(0);
// use yellow color to highlight the selected atoms
const atomColors = new Array(this.atoms.getAtomsCount()).fill(new THREE.Color(0xffff00));
this.highlightAtomsMesh = drawAtoms({ scene: this.tjs.scene, atoms: this.atoms, atomScales: atomScales, colors: atomColors, radiusType: this.radiusType, materialType: "Basic" });
this.tjs.scene.add(this.highlightAtomsMesh);
this.highlightAtomsMesh = drawAtoms({
scene: this.tjs.scene,
atoms: this.atoms,
atomScales: atomScales,
colors: atomColors,
radiusType: this.radiusType,
materialType: "Basic",
data_type: "highlight",
});
this.atomsMesh.add(this.highlightAtomsMesh);
this.highlightAtomsMesh.material.opacity = 0.6;
this.updateHighlightAtomsMesh(this.selectedAtomsIndices);
}
Expand Down
5 changes: 2 additions & 3 deletions src/atoms/draw_atoms.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { materials } from "../tools/materials.js";

const Radii = { Covalent: covalentRadii, VDW: vdwRadii };

export function drawAtoms({ scene, atoms, atomScales, colors, radiusType = "Covalent", materialType = "Standard" }) {
export function drawAtoms({ atoms, atomScales, colors, radiusType = "Covalent", materialType = "Standard", data_type = "atom" }) {
console.time("drawAtoms Time");
// console.log("atomScales: ", atomScales);
console.log("Draw Atoms: ", +atoms.symbols.length, " atoms");
Expand Down Expand Up @@ -45,7 +45,7 @@ export function drawAtoms({ scene, atoms, atomScales, colors, radiusType = "Cova
// Set color
instancedMesh.setColorAt(globalIndex, colors[globalIndex]);
});
instancedMesh.userData.type = "atom";
instancedMesh.userData.type = data_type;
instancedMesh.userData.uuid = atoms.uuid;
// the default objectMode for atoms is "edit"
instancedMesh.userData.objectMode = "edit";
Expand All @@ -57,7 +57,6 @@ export function drawAtoms({ scene, atoms, atomScales, colors, radiusType = "Cova
instancedMesh.instanceColor.needsUpdate = true;
}

scene.add(instancedMesh);
console.timeEnd("drawAtoms Time");
return instancedMesh;
}
2 changes: 1 addition & 1 deletion src/atoms/plugins/bond.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export class BondManager {
atomColors = this.viewer.atomColors;
}
this.bondMesh = drawStick(this.viewer.atoms, this.bondList, this.buildBondDict(), this.viewer.bondRadius, this.viewer._materialType, atomColors);
this.scene.add(this.bondMesh);
return this.bondMesh;
}

updateBondMesh(atomIndex = null, atoms = null) {
Expand Down
1 change: 1 addition & 0 deletions src/atoms/plugins/isosurface.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class Isosurface {
drawIsosurfaces() {
/* Draw isosurfaces */
if (this.volumetricData === null) {
console.log("No volumetric data is set");
return;
}
console.log("drawIsosurfaces");
Expand Down
14 changes: 7 additions & 7 deletions src/atoms/plugins/polyhedra.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export class PolyhedraManager {
this.viewer = viewer;
this.scene = this.viewer.tjs.scene;
this.settings = [];
this.meshes = [];
// create a group to store the polyhedra meshes
this.meshes = new THREE.Group();
this.init();
}

Expand Down Expand Up @@ -81,9 +82,7 @@ export class PolyhedraManager {

clearMeshes() {
/* Remove highlighted atom meshes from the selectedAtomsMesh group */
this.meshes.forEach((mesh) => {
clearObject(this.scene, mesh);
});
clearObject(this.scene, this.meshes);
}

drawPolyhedras() {
Expand All @@ -92,10 +91,11 @@ export class PolyhedraManager {
if (this.viewer.debug) {
console.log("polyhedras: ", polyhedras);
}
this.meshes = drawPolyhedras(this.viewer.atoms, polyhedras, this.viewer.bondManager.bondList, this.viewer._colorType, this.viewer._materialType);
this.meshes.forEach((mesh) => {
this.scene.add(mesh);
const meshes = drawPolyhedras(this.viewer.atoms, polyhedras, this.viewer.bondManager.bondList, this.viewer._colorType, this.viewer._materialType);
meshes.forEach((mesh) => {
this.meshes.add(mesh);
});
return this.meshes;
}

updatePolyhedraMesh(atomIndex = null, atoms = null) {
Expand Down
42 changes: 16 additions & 26 deletions src/controls/TransformControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export class TransformControls {
this.centroidNDC = new THREE.Vector2();
this.initialAtomPositions = new Map(); // To store initial positions of selected atoms
this.initialObjectState = new Map(); // To store initial state of selected objects
this.viewerRect = this.tjs.containerElement.getBoundingClientRect();
// Get the camera's forward direction (negative z-axis in world space)
this.cameraDirection = new THREE.Vector3(0, 0, -1);
}
Expand All @@ -43,6 +42,7 @@ export class TransformControls {
enterMode(mode, mousePosition) {
this.mode = mode;
console.log("Enter mode: ", this.mode);
this.cameraDirection = new THREE.Vector3(0, 0, -1);
this.cameraDirection.applyQuaternion(this.tjs.camera.quaternion);
if (this.mode === "translate") {
// Get the camera's forward direction (negative z-axis in world space)
Expand Down Expand Up @@ -74,17 +74,15 @@ export class TransformControls {
// Create a translate operation
if (this.mode === "translate") {
const translateVector = this.getTranslateVector(this.eventHandler.currentMousePosition, this.initialMousePosition);
console.log("Translate vector: ", translateVector);
const translateOperation = new TranslateOperation(this.weas, translateVector);
const translateOperation = new TranslateOperation({ weas: this.weas, vector: translateVector });
this.weas.ops.execute(translateOperation, false);
} else if (this.mode === "rotate") {
const rotationAngle = this.getRotationAngle(this.eventHandler.currentMousePosition, this.initialMousePosition);
const rotateOperation = new RotateOperation(this.weas, this.cameraDirection, rotationAngle);
const rotateOperation = new RotateOperation({ weas: this.weas, axis: this.cameraDirection, angle: rotationAngle });
this.weas.ops.execute(rotateOperation, false);
} else if (this.mode === "scale") {
const scaleVector = this.getScaleVector(this.eventHandler.currentMousePosition, this.initialMousePosition);
console.log("Scale vector: ", scaleVector);
const scaleOperation = new ScaleOperation(this.weas, scaleVector);
const scaleOperation = new ScaleOperation({ weas: this.weas, scale: scaleVector });
this.weas.ops.execute(scaleOperation, false);
} else {
console.log("Invalid mode");
Expand Down Expand Up @@ -175,9 +173,15 @@ export class TransformControls {
this.weas.objectManager.translateSelectedObjects(translateVector);
}

getNDC(mousePosition) {
return new THREE.Vector2(((mousePosition.x - this.tjs.viewerRect.left) / this.tjs.viewerRect.width) * 2 - 1, -((mousePosition.y - this.tjs.viewerRect.top) / this.tjs.viewerRect.height) * 2 + 1);
}

getTranslateVector(currentMousePosition, previousMousePosition) {
const currentWorldPosition = getWorldPositionFromScreen(currentMousePosition.x, currentMousePosition.y, this.tjs.camera, this.translatePlane);
const previousWorldPosition = getWorldPositionFromScreen(previousMousePosition.x, previousMousePosition.y, this.tjs.camera, this.translatePlane);
const newNDC = this.getNDC(currentMousePosition);
const currentWorldPosition = getWorldPositionFromScreen(this.tjs.camera, newNDC, this.translatePlane);
const initialNDC = this.getNDC(previousMousePosition);
const previousWorldPosition = getWorldPositionFromScreen(this.tjs.camera, initialNDC, this.translatePlane);
return currentWorldPosition.sub(previousWorldPosition);
}

Expand All @@ -200,15 +204,8 @@ export class TransformControls {
}

getScaleVector(currentMousePosition, previousMousePosition) {
const initialNDC = new THREE.Vector2(
((previousMousePosition.x - this.viewerRect.left) / this.viewerRect.width) * 2 - 1,
-((previousMousePosition.y - this.viewerRect.top) / this.viewerRect.height) * 2 + 1,
);

const newNDC = new THREE.Vector2(
((currentMousePosition.x - this.viewerRect.left) / this.viewerRect.width) * 2 - 1,
-((currentMousePosition.y - this.viewerRect.top) / this.viewerRect.height) * 2 + 1,
);
const initialNDC = this.getNDC(previousMousePosition);
const newNDC = this.getNDC(currentMousePosition);
if (initialNDC.equals(newNDC)) {
return; // Skip further processing
}
Expand All @@ -221,15 +218,8 @@ export class TransformControls {
}

getRotationAngle(currentMousePosition, previousMousePosition) {
const initialNDC = new THREE.Vector2(
((previousMousePosition.x - this.viewerRect.left) / this.viewerRect.width) * 2 - 1,
-((previousMousePosition.y - this.viewerRect.top) / this.viewerRect.height) * 2 + 1,
);

const newNDC = new THREE.Vector2(
((currentMousePosition.x - this.viewerRect.left) / this.viewerRect.width) * 2 - 1,
-((currentMousePosition.y - this.viewerRect.top) / this.viewerRect.height) * 2 + 1,
);
const initialNDC = this.getNDC(previousMousePosition);
const newNDC = this.getNDC(currentMousePosition);
if (initialNDC.equals(newNDC)) {
console.log("No mouse movement detected, skipping rotation.");
return; // Skip further processing
Expand Down
39 changes: 39 additions & 0 deletions src/core/Camera.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as THREE from "three";

export class OrthographicCamera extends THREE.OrthographicCamera {
constructor(left, right, top, bottom, near, far, tjs = null) {
super(left, right, top, bottom, near, far);
this.tjs = tjs;
}

// Custom method to update zoom
updateZoom(value) {
if (this.zoom !== value) {
this.zoom = value;
this.updateProjectionMatrix(); // Required to apply the zoom change
this.dispatchObjectEvent({
data: value,
action: "zoom",
catalog: "camera",
});
}
}

// Custom method to update position
updatePosition(x, y, z) {
const newPos = new THREE.Vector3(x, y, z);
if (!this.position.equals(newPos)) {
this.position.copy(newPos);
this.dispatchObjectEvent({
data: [x, y, z],
action: "position",
catalog: "camera",
});
}
}

dispatchObjectEvent(data) {
const event = new CustomEvent("weas", { detail: data });
this.tjs.containerElement.dispatchEvent(event);
}
}
27 changes: 18 additions & 9 deletions src/core/ObjectManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,42 @@ export class ObjectManager {
constructor(weas) {
this.weas = weas;
this.selectionManager = weas.selectionManager;
this.sceneManager = weas.tjs.sceneManager;
this.scene = weas.tjs.scene;
}

translateSelectedObjects(translateVector) {
this.selectionManager.selectedObjects.forEach((object) => {
translateSelectedObjects(translateVector, selectedObjects = null) {
if (selectedObjects === null) {
selectedObjects = this.selectionManager.selectedObjects;
}
selectedObjects.forEach((object) => {
const initialPosition = object.position.clone();
object.position.copy(initialPosition.add(translateVector));
});
}

rotateSelectedObjects(rotationAxis, rotationAngle) {
rotateSelectedObjects(rotationAxis, rotationAngle, selectedObjects = null) {
if (selectedObjects === null) {
selectedObjects = this.selectionManager.selectedObjects;
}
rotationAxis = rotationAxis.normalize();
rotationAngle = THREE.MathUtils.degToRad(rotationAngle);
this.selectionManager.selectedObjects.forEach((object) => {
selectedObjects.forEach((object) => {
object.rotateOnAxis(rotationAxis, -rotationAngle);
});
}

deleteSelectedObjects() {
this.selectionManager.selectedObjects.forEach((object) => {
clearObject(this.sceneManager.scene, object);
clearObject(this.scene, object);
});
this.selectionManager.clearSelection();
}

scaleSelectedObjects(scale) {
this.selectionManager.selectedObjects.forEach((object) => {
scaleSelectedObjects(scale, selectedObjects = null) {
if (selectedObjects === null) {
selectedObjects = this.selectionManager.selectedObjects;
}
selectedObjects.forEach((object) => {
object.scale.multiply(scale);
});
}
Expand All @@ -41,7 +50,7 @@ export class ObjectManager {
this.selectionManager.selectedObjects.forEach((object) => {
const clone = object.clone();
clone.position.add(new THREE.Vector3(1, 1, 1));
this.sceneManager.scene.add(clone);
this.scene.add(clone);
newObjects.push(clone);
});
this.selectionManager.selectedObjects = newObjects;
Expand Down
Loading
Loading