Skip to content

Commit c15608e

Browse files
committed
feat: first implementation of coordiantes measurement in wave
1 parent b3e4bd3 commit c15608e

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

dist/components/ThreeDEditor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ export class ThreeDEditor extends React.Component {
560560
handleToggleCoordinatesShown() {
561561
const { measurementsSettings } = this.state;
562562
const { isCoordinatesShown, isDistanceShown, isAnglesShown } = measurementsSettings;
563+
// TODO: avoid repetition of exclusive toggling logic
563564
if (isDistanceShown) {
564565
this.offMeasurementParam("isDistanceShown");
565566
}

src/components/ThreeDEditor.jsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export class ThreeDEditor extends React.Component {
5858
measurementsSettings: {
5959
isDistanceShown: false,
6060
isAnglesShown: false,
61+
isCoordinatesShown: false,
6162
measurementLabelsShown: false,
6263
distance: 0,
6364
angle: 0,
@@ -103,6 +104,7 @@ export class ThreeDEditor extends React.Component {
103104
this.handleChemicalConnectivityFactorChange.bind(this);
104105
this.handleToggleDistanceShown = this.handleToggleDistanceShown.bind(this);
105106
this.handleToggleAnglesShown = this.handleToggleAnglesShown.bind(this);
107+
this.handleToggleCoordinatesShown = this.handleToggleCoordinatesShown.bind(this);
106108
this.handleSetState = this.handleSetState.bind(this);
107109
this.handleDeleteConnection = this.handleDeleteConnection.bind(this);
108110
this.handleResetMeasurements = this.handleResetMeasurements.bind(this);
@@ -290,14 +292,14 @@ export class ThreeDEditor extends React.Component {
290292
this.setState({ isThreejsEditorModalShown: !isThreejsEditorModalShown });
291293
}
292294

293-
// TODO: reset the colors for other buttons in the panel on call to the function below
294295
handleResetViewer() {
295296
const { measurementsSettings } = this.state;
296297
this.setState({
297298
measurementsSettings: {
298299
...measurementsSettings,
299300
isDistanceShown: false,
300301
isAnglesShown: false,
302+
isCoordinatesShown: false,
301303
},
302304
});
303305
this.WaveComponent.initViewer();
@@ -396,6 +398,25 @@ export class ThreeDEditor extends React.Component {
396398
}
397399
}
398400

401+
handleToggleCoordinatesShown() {
402+
const { measurementsSettings } = this.state;
403+
const { isCoordinatesShown, isDistanceShown, isAnglesShown } = measurementsSettings;
404+
405+
// TODO: avoid repetition of exclusive toggling logic
406+
if (isDistanceShown) {
407+
this.offMeasurementParam("isDistanceShown");
408+
}
409+
if (isAnglesShown) {
410+
this.offMeasurementParam("isAnglesShown");
411+
}
412+
413+
if (!isCoordinatesShown) {
414+
this.onMeasurementParam("isCoordinatesShown", "isDistanceShown");
415+
} else {
416+
this.offMeasurementParam("isCoordinatesShown");
417+
}
418+
}
419+
399420
/**
400421
* Returns a cover div to cover the area and prevent user interaction with component
401422
*/
@@ -545,7 +566,7 @@ export class ThreeDEditor extends React.Component {
545566

546567
getMeasurementsActions = () => {
547568
const { measurementsSettings } = this.state;
548-
const { isDistanceShown, isAnglesShown } = measurementsSettings;
569+
const { isDistanceShown, isAnglesShown, isCoordinatesShown } = measurementsSettings;
549570
return [
550571
{
551572
id: "Distances",
@@ -563,6 +584,14 @@ export class ThreeDEditor extends React.Component {
563584
onClick: this.handleToggleAnglesShown,
564585
shouldMenuStayOpened: true,
565586
},
587+
{
588+
id: "Coordinates",
589+
content: "Coordinates [C]",
590+
rightIcon: this.getCheckmark(isCoordinatesShown),
591+
leftIcon: <GpsFixed />,
592+
onClick: this.handleToggleCoordinatesShown,
593+
shouldMenuStayOpened: true,
594+
},
566595
{
567596
id: "Delete",
568597
content: "Delete connection [X]",

src/mixins/measurement.js

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,13 @@ export const MeasurementMixin = (superclass) =>
306306

307307
if (intersectItem.type === "Mesh") {
308308
const isAlreadySelected = intersectItem.userData.selected;
309+
310+
// Get atom position and draw coordinates if enabled
311+
const position = new THREE.Vector3().setFromMatrixPosition(
312+
intersectItem.matrixWorld,
313+
);
314+
this.drawCoordinateText(position, intersectItem);
315+
309316
if (this.measurementSettings.isDistanceShown)
310317
this.addIfLastNotSame(intersectItem);
311318
if (this.measurementSettings.isAnglesShown)
@@ -347,7 +354,17 @@ export const MeasurementMixin = (superclass) =>
347354
getIntersectedObjects(event) {
348355
this.checkMouseCoordinates(event);
349356
const atomGroup = this.getAtomGroups();
350-
const searchedIntersects = [...atomGroup];
357+
const searchedIntersects = [];
358+
359+
// Always include atoms if any measurement type is enabled
360+
if (
361+
this.measurementSettings.isDistanceShown ||
362+
this.measurementSettings.isAnglesShown ||
363+
this.measurementSettings.isCoordinatesShown
364+
) {
365+
searchedIntersects.push(...atomGroup);
366+
}
367+
351368
if (this.measurementSettings.isDistanceShown) {
352369
searchedIntersects.push(...this.atomConnections.children);
353370
}
@@ -544,6 +561,13 @@ export const MeasurementMixin = (superclass) =>
544561
atom.userData.selected = false;
545562
this.selectedAtoms.pop();
546563
atom.material.emissive.setHex(atom.currentHex);
564+
565+
// Remove coordinate label if it exists
566+
if (atom.userData.coordinateLabel) {
567+
this.measurementLabels.remove(atom.userData.coordinateLabel);
568+
atom.userData.coordinateLabel = null;
569+
}
570+
547571
this.render();
548572
}
549573
}
@@ -627,11 +651,16 @@ export const MeasurementMixin = (superclass) =>
627651
this.deleteConnection();
628652
});
629653
}
630-
631654
if (this.selectedAtoms.length) {
632655
this.selectedAtoms.forEach((atom) => {
633656
atom.userData.selected = false;
634657
atom.material.emissive.setHex(atom.currentHex);
658+
659+
// Remove coordinate labels
660+
if (atom.userData.coordinateLabel) {
661+
this.measurementLabels.remove(atom.userData.coordinateLabel);
662+
atom.userData.coordinateLabel = null;
663+
}
635664
});
636665
this.selectedAtoms = [];
637666
}
@@ -683,4 +712,43 @@ export const MeasurementMixin = (superclass) =>
683712

684713
return this.radiansToDegrees(Math.acos(angle)).toFixed(2);
685714
}
715+
716+
/**
717+
* Function that draws coordinate text.
718+
* @param {THREE.Vector3} position - position of the atom
719+
* @param {Object} atom - the atom object
720+
*/
721+
drawCoordinateText(position, atom) {
722+
// Remove existing coordinate label if it exists
723+
if (atom.userData.coordinateLabel) {
724+
this.measurementLabels.remove(atom.userData.coordinateLabel);
725+
}
726+
727+
// Only show coordinates if coordinate measurement is enabled
728+
if (!this.measurementSettings.isCoordinatesShown) {
729+
return;
730+
}
731+
732+
const label = this.createLabelSprite(
733+
`(${position.x.toFixed(3)}, ${position.y.toFixed(3)}, ${position.z.toFixed(3)})`,
734+
`coordinates-for-${atom.uuid}`,
735+
);
736+
737+
// Position the label up and to the right of the atom
738+
const labelPosition = position.clone();
739+
labelPosition.y += 0.0;
740+
labelPosition.x += 0.0;
741+
742+
label.position.copy(labelPosition);
743+
label.visible = true;
744+
label.scale.set(1.0, 1.0, 1.0);
745+
label.lookAt(this.camera.position);
746+
747+
// Store reference to label in atom's userData
748+
atom.userData.coordinateLabel = label;
749+
750+
this.measurementLabels.add(label);
751+
this.scene.add(this.measurementLabels);
752+
this.render();
753+
}
686754
};

0 commit comments

Comments
 (0)