Skip to content

Commit a0f7f3f

Browse files
committed
added settings option ATOM_LEVEL_SELECTION with improved selection visualization by splitting all bond sticks into two parts
1 parent b9cef88 commit a0f7f3f

22 files changed

+311
-182
lines changed

src/main/java/org/openmolecules/fx/tasks/V3DShapeAlignerFromFile.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private void run() {
5656
for(PheSAMolecule fitShape : mFitShapes) {
5757
dhs.getSimilarity(refShape, fitShape);
5858
try {
59-
fittedFXMols.add(new V3DMolecule(dhs.getPreviousAlignment()[1], V3DMolecule.getNextID(),V3DMolecule.MoleculeRole.LIGAND, mScene.mayOverrideHydrogenColor()));
59+
fittedFXMols.add(new V3DMolecule(dhs.getPreviousAlignment()[1], V3DMolecule.getNextID(),V3DMolecule.MoleculeRole.LIGAND, mScene.isOverrideHydrogenColor(), false));
6060
}
6161
catch(Exception e) {
6262
continue;

src/main/java/org/openmolecules/fx/tasks/V3DShapeAlignment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void run() {
5252
dhs.getSimilarity(refShape, fitShape);
5353

5454
try {
55-
fittedFXMols.add(new V3DMolecule(dhs.getPreviousAlignment()[1], V3DMolecule.getNextID(),V3DMolecule.MoleculeRole.LIGAND, mScene.mayOverrideHydrogenColor()));
55+
fittedFXMols.add(new V3DMolecule(dhs.getPreviousAlignment()[1], V3DMolecule.getNextID(),V3DMolecule.MoleculeRole.LIGAND, mScene.isOverrideHydrogenColor(), false));
5656
}
5757
catch(Exception e) {
5858
continue;

src/main/java/org/openmolecules/fx/viewer3d/V3DMolecule.java

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
import org.openmolecules.mesh.Cone;
5252
import org.openmolecules.mesh.MoleculeSurfaceAlgorithm;
5353
import org.openmolecules.render.MoleculeArchitect;
54-
import org.openmolecules.render.MoleculeBuilder;
54+
import org.openmolecules.render.RoleHelper;
5555
import org.openmolecules.render.TorsionStrainVisualization;
5656

5757
import java.util.*;
@@ -66,7 +66,7 @@ public class V3DMolecule extends V3DRotatableGroup {
6666
private static final int DEFAULT_SURFACE_COLOR_MODE = SURFACE_COLOR_PLAIN;
6767

6868
public enum SurfaceMode {NONE(0), WIRES(1),FILLED(2);
69-
public int mode;
69+
public final int mode;
7070
SurfaceMode(int mode) {
7171
this.mode = mode;
7272
}
@@ -105,6 +105,7 @@ public enum SurfaceMode {NONE(0), WIRES(1),FILLED(2);
105105
private TorsionStrainVisualization torsionStrainVis;
106106
private ArrayList<AtomIndexLabel> mLabelList;
107107
private int mnUnconnectedFragments;
108+
private boolean mSplitAllBonds;
108109

109110
public enum MoleculeRole{
110111
LIGAND { public String toString(){
@@ -140,6 +141,21 @@ public V3DMolecule(StereoMolecule mol) {
140141
this(mol, MoleculeArchitect.CONSTRUCTION_MODE_STICKS, MoleculeArchitect.HYDROGEN_MODE_DEFAULT, 0, MoleculeRole.LIGAND );
141142
}
142143

144+
/**
145+
* Creates a V3DMolecule from the given molecule with the following default specification:<br>
146+
* - construction mode: sticks<br>
147+
* - default hydrogen mode, i.e. shows all explicit hydrogens<br>
148+
* - shows no surface<br>
149+
* - id = 0<br>
150+
* - group = 0<br>
151+
* - role = LIGAND
152+
* @param mol
153+
* @param splitAllBonds
154+
*/
155+
public V3DMolecule(StereoMolecule mol, boolean overrideHydrogen, boolean splitAllBonds) {
156+
this(mol, MoleculeArchitect.CONSTRUCTION_MODE_STICKS, MoleculeArchitect.HYDROGEN_MODE_DEFAULT, 0, MoleculeRole.LIGAND, overrideHydrogen, splitAllBonds );
157+
}
158+
143159
/**
144160
* Creates a V3DMolecule from the given molecule with the following default specification:<br>
145161
* - construction mode: sticks<br>
@@ -151,8 +167,8 @@ public V3DMolecule(StereoMolecule mol, int id, MoleculeRole role) {
151167
this(mol, MoleculeArchitect.CONSTRUCTION_MODE_STICKS, MoleculeArchitect.HYDROGEN_MODE_DEFAULT, id, role );
152168
}
153169

154-
public V3DMolecule(StereoMolecule mol, int id, MoleculeRole role, boolean overrideHydrogen) {
155-
this(mol, MoleculeArchitect.CONSTRUCTION_MODE_STICKS, MoleculeArchitect.HYDROGEN_MODE_DEFAULT, id, role, overrideHydrogen);
170+
public V3DMolecule(StereoMolecule mol, int id, MoleculeRole role, boolean overrideHydrogen, boolean splitAllBonds) {
171+
this(mol, MoleculeArchitect.CONSTRUCTION_MODE_STICKS, MoleculeArchitect.HYDROGEN_MODE_DEFAULT, id, role, overrideHydrogen, splitAllBonds);
156172
}
157173

158174
/**
@@ -174,12 +190,12 @@ public V3DMolecule(StereoMolecule mol, int constructionMode, int id, MoleculeRol
174190
*/
175191
public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.HydrogenMode hydrogenMode, int id, MoleculeRole role) {
176192
this(mol, constructionMode, hydrogenMode, SurfaceMode.NONE,
177-
DEFAULT_SURFACE_COLOR_MODE, null, DEFAULT_SURFACE_TRANSPARENCY, id, role, true);
193+
DEFAULT_SURFACE_COLOR_MODE, null, DEFAULT_SURFACE_TRANSPARENCY, id, role, true, false);
178194
}
179195

180-
public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.HydrogenMode hydrogenMode, int id, MoleculeRole role, boolean overrideHydrogen) {
196+
public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.HydrogenMode hydrogenMode, int id, MoleculeRole role, boolean overrideHydrogen, boolean splitAllBonds) {
181197
this(mol, constructionMode, hydrogenMode, SurfaceMode.NONE,
182-
DEFAULT_SURFACE_COLOR_MODE, null, DEFAULT_SURFACE_TRANSPARENCY, id, role, overrideHydrogen);
198+
DEFAULT_SURFACE_COLOR_MODE, null, DEFAULT_SURFACE_TRANSPARENCY, id, role, overrideHydrogen, splitAllBonds);
183199
}
184200

185201
/**
@@ -191,10 +207,14 @@ public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.H
191207
* @param surfaceColorMode DEFAULT_SURFACE_COLOR_MODE or one of the SurfaceMesh.SURFACE_COLOR_xxx modes
192208
* @param surfaceColor null or explicit surface color used for some color modes
193209
* @param transparency
210+
* @param id
211+
* @param role
212+
* @param overrideHydrogens whether hydrogen atoms are drawn in the molecule override color
213+
* @param splitAllBonds whether all bonds shall be constructed from two cylinders (allowing better selection coloring)
194214
*/
195215
public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.HydrogenMode hydrogenMode,
196216
SurfaceMode surfaceMode, int surfaceColorMode, Color surfaceColor, double transparency,
197-
int id, MoleculeRole role, boolean overrideHydrogens) {
217+
int id, MoleculeRole role, boolean overrideHydrogens, boolean splitAllBonds) {
198218
super(mol.getName());
199219
mMol = mol;
200220
mnUnconnectedFragments = mMol.getFragmentNumbers(new int[mMol.getAllAtoms()], false, true);
@@ -207,6 +227,7 @@ public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.H
207227
mSelectedProperty = new SimpleBooleanProperty(false);
208228
mSelectedProperty.addListener((v,ov,nv) -> updateSelectionAppearance());
209229
mOverrideHydrogens = overrideHydrogens;
230+
mSplitAllBonds = splitAllBonds;
210231
int surfaceCount = MoleculeSurfaceAlgorithm.SURFACE_TYPE.length;
211232
mSurface = new MeshView[surfaceCount];
212233
mSurfaceMesh = new SurfaceMesh[surfaceCount];
@@ -235,9 +256,7 @@ public V3DMolecule(StereoMolecule mol, int constructionMode, MoleculeArchitect.H
235256
}
236257

237258
constructMaterials();
238-
V3DMoleculeBuilder builder = new V3DMoleculeBuilder(this);
239-
// we cannot center pre-aligned conformers builder.centerMolecule(conformer);
240-
builder.buildMolecule();
259+
new V3DMoleculeBuilder(this).buildMolecule();
241260

242261
if (surfaceMode != SurfaceMode.NONE) {
243262
mSurfaceMesh[0] = new SurfaceMesh(mMol, 0, surfaceColorMode, getNeutralColor(0), 1.0 - transparency, createSurfaceCutter());
@@ -639,7 +658,11 @@ public IntegerProperty IDProperty() {
639658
public boolean isSelected() {
640659
return mSelectedProperty.get();
641660
}
642-
661+
662+
public boolean isSplitAllBonds() {
663+
return mSplitAllBonds;
664+
}
665+
643666
public boolean overrideHydrogens() {
644667
return mOverrideHydrogens;
645668
}
@@ -881,29 +904,68 @@ private boolean pickedAtomsAreStrand() {
881904
public void toggleSelection() {
882905
mSelectedProperty.set(!mSelectedProperty.get());
883906
}
884-
907+
908+
/**
909+
* Updates the selection of the entire molecule
910+
*/
885911
private void updateSelectionAppearance() {
912+
// Complete molecule selection
886913
for (Node node:getChildren()) {
887914
NodeDetail detail = (NodeDetail)node.getUserData();
888915
if (detail != null && !detail.isTransparent()) {
889916
detail.setSelected(mSelectedProperty.get());
890917
updateAppearance(node);
891918
}
892919
}
920+
893921
for (int atom=0; atom<mMol.getAllAtoms(); atom++)
894922
mMol.setAtomSelection(atom, mSelectedProperty.get());
895-
}
896-
897-
898-
923+
}
899924

900925
/**
901926
* @param polygon screen coordinate polygon defining the selection
902927
* @param mode 0: normal, 1:add, 2:subtract
903928
* @param paneOnScreen top let point of parent pane on screen
904929
*/
905930
public void select(Polygon polygon, int mode, Point2D paneOnScreen) {
906-
mSelectedProperty.set(!mSelectedProperty.get());
931+
boolean selectionChanged = false;
932+
for (Node node:getChildren()) {
933+
NodeDetail detail = (NodeDetail)node.getUserData();
934+
if (detail != null && !detail.isTransparent() && detail.isAtom()) {
935+
boolean isSelected = (polygon != null)
936+
&& polygon.contains(node.localToScreen(0, 0, 0).subtract(paneOnScreen));
937+
if (mode == 1)
938+
isSelected |= detail.isSelected();
939+
else if (mode == 2)
940+
isSelected = detail.isSelected() && !isSelected;
941+
if (isSelected != detail.isSelected()) {
942+
detail.setSelected(isSelected);
943+
updateAppearance(node);
944+
mMol.setAtomSelection(detail.getAtom(), isSelected);
945+
selectionChanged = true;
946+
}
947+
}
948+
}
949+
if (selectionChanged) {
950+
for (Node node:getChildren()) {
951+
NodeDetail detail = (NodeDetail)node.getUserData();
952+
if (detail != null && !detail.isTransparent()) {
953+
if (detail.isBond()) {
954+
int bond = detail.getBond();
955+
int bondAtom = detail.getBondAtom(mMol);
956+
boolean isSelected = (bondAtom != -1) ? mMol.isSelectedAtom(bondAtom)
957+
: mMol.isSelectedAtom(mMol.getBondAtom(0, bond))
958+
&& mMol.isSelectedAtom(mMol.getBondAtom(1, bond));
959+
if (isSelected != detail.isSelected()) {
960+
detail.setSelected(isSelected);
961+
updateAppearance(node);
962+
}
963+
}
964+
}
965+
}
966+
}
967+
968+
/* mSelectedProperty.set(!mSelectedProperty.get());
907969
for (Node node:getChildren()) {
908970
NodeDetail detail = (NodeDetail)node.getUserData();
909971
if (detail != null && !detail.isTransparent()) {
@@ -921,7 +983,7 @@ else if (mode == 2)
921983
mMol.setAtomSelection(atom, isSelected);
922984
}
923985
}
924-
}
986+
}*/
925987
}
926988

927989
// Delete all flagged atoms except those that have a direct connection
@@ -1116,7 +1178,7 @@ public void updateAppearance(Node node) {
11161178
&& ((NodeDetail)shape.getUserData()).getMaterial().getDiffuseColor().getOpacity() == 0.0);
11171179

11181180
if (!isInvisibleShape) {
1119-
float scale = (shape == mHighlightedShape || mPickedAtomList.contains(shape)) ? HIGHLIGHT_SCALE : 1.0f;
1181+
float scale = (shape == mHighlightedShape || mPickedAtomList.contains(shape) /*|| isSelectedAtom*/) ? HIGHLIGHT_SCALE : 1.0f;
11201182
if (shape.getScaleX() != scale) {
11211183
shape.setScaleX(scale);
11221184
shape.setScaleY(scale);
@@ -1236,7 +1298,7 @@ private void updateTemporaryAtomSpheres() {
12361298
sphere.setTranslateX(mMol.getAtomX(atom));
12371299
sphere.setTranslateY(mMol.getAtomY(atom));
12381300
sphere.setTranslateZ(mMol.getAtomZ(atom));
1239-
sphere.setUserData(new NodeDetail(material, MoleculeBuilder.ROLE_IS_ATOM | atom, isOverridable));
1301+
sphere.setUserData(new NodeDetail(material, RoleHelper.createAtomRole(atom), isOverridable));
12401302
getChildren().add(sphere);
12411303
mTemporaryAtomSpheres.add(sphere);
12421304
}

src/main/java/org/openmolecules/fx/viewer3d/V3DMoleculeBuilder.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public V3DMoleculeBuilder(V3DMolecule v3DMolecule) {
4848
mArchitect = new MoleculeArchitect(this);
4949
mArchitect.setHydrogenMode(v3DMolecule.getHydrogenMode());
5050
mArchitect.setConstructionMode(v3DMolecule.getConstructionMode());
51-
mArchitect.setShowSelection(true);
51+
mArchitect.setSplitAllBonds(v3DMolecule.isSplitAllBonds());
5252
mV3DMolecule = v3DMolecule;
5353
calculateDivisions();
5454
}
@@ -86,11 +86,12 @@ public void addAtomSphere(int role, Coordinates c, double radius, int argb) {
8686
argb == MoleculeArchitect.getAtomicNoARGB(1)
8787
|| argb == MoleculeArchitect.getAtomicNoARGB(6)
8888
: argb == MoleculeArchitect.getAtomicNoARGB(6);
89-
sphere.setUserData(new NodeDetail((PhongMaterial)sphere.getMaterial(), role, isOverridable));
89+
NodeDetail detail = new NodeDetail((PhongMaterial)sphere.getMaterial(), role, isOverridable);
90+
sphere.setUserData(detail);
9091

9192
// dotted bonds also use addAtomSphere()...
92-
if ((role & MoleculeBuilder.ROLE_IS_ATOM) != 0) {
93-
if (mV3DMolecule.getMolecule().isSelectedAtom(role & MoleculeBuilder.ROLE_INDEX_BITS)) {
93+
if (detail.isAtom()) {
94+
if (mV3DMolecule.getMolecule().isSelectedAtom(detail.getAtom())) {
9495
((NodeDetail)sphere.getUserData()).setSelected(true);
9596
mV3DMolecule.updateAppearance(sphere);
9697
}
@@ -108,11 +109,14 @@ public void addBondCylinder(int role, double radius, double length, Coordinates
108109
|| argb == MoleculeArchitect.BALL_AND_STICK_STICK_COLOR
109110
: argb == MoleculeArchitect.getAtomicNoARGB(6)
110111
|| argb == MoleculeArchitect.BALL_AND_STICK_STICK_COLOR;
111-
cylinder.setUserData(new NodeDetail((PhongMaterial)cylinder.getMaterial(), role, isOverridable));
112+
NodeDetail detail = new NodeDetail((PhongMaterial)cylinder.getMaterial(), role, isOverridable);
113+
cylinder.setUserData(detail);
112114
StereoMolecule mol = mV3DMolecule.getMolecule();
113-
int bond = role & MoleculeBuilder.ROLE_INDEX_BITS;
114-
if (mol.isSelectedAtom(mol.getBondAtom(0, bond)) && mol.isSelectedAtom(mol.getBondAtom(1, bond))) {
115-
((NodeDetail)cylinder.getUserData()).setSelected(true);
115+
int bond = detail.getBond();
116+
int bondAtom = detail.getBondAtom(mol);
117+
if ((bondAtom != -1 && mol.isSelectedAtom(bondAtom))
118+
|| (mol.isSelectedAtom(mol.getBondAtom(0, bond)) && mol.isSelectedAtom(mol.getBondAtom(1, bond)))) {
119+
detail.setSelected(true);
116120
mV3DMolecule.updateAppearance(cylinder);
117121
}
118122
}
@@ -126,9 +130,10 @@ public void addAtomCone(int role, double radius, double height, Coordinates cent
126130
|| argb == MoleculeArchitect.BALL_AND_STICK_STICK_COLOR
127131
: argb == MoleculeArchitect.getAtomicNoARGB(6)
128132
|| argb == MoleculeArchitect.BALL_AND_STICK_STICK_COLOR;
129-
cone.setUserData(new NodeDetail((PhongMaterial)cone.getMaterial(), role, isOverridable));
130-
if ((role & MoleculeBuilder.ROLE_IS_ATOM) != 0)
131-
((NodeDetail)cone.getUserData()).setSelected(mV3DMolecule.getMolecule().isSelectedAtom(role & MoleculeBuilder.ROLE_INDEX_BITS));
133+
NodeDetail detail = new NodeDetail((PhongMaterial)cone.getMaterial(), role, isOverridable);
134+
cone.setUserData(detail);
135+
if (detail.isAtom())
136+
detail.setSelected(mV3DMolecule.getMolecule().isSelectedAtom(detail.getAtom()));
132137
}
133138

134139
private void calculateDivisions() {

src/main/java/org/openmolecules/fx/viewer3d/V3DMoleculeUpdater.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,7 @@
1313
import org.openmolecules.fx.viewer3d.nodes.NodeDetail;
1414
import org.openmolecules.fx.viewer3d.nodes.VolumeSphere;
1515
import org.openmolecules.fx.viewer3d.nodes.AbstractPPNode;
16-
import org.openmolecules.render.MoleculeArchitect;
17-
import org.openmolecules.render.MoleculeBuilder;
18-
import org.openmolecules.render.PharmacophoreArchitect;
19-
import org.openmolecules.render.PharmacophoreBuilder;
20-
import org.openmolecules.render.TorsionStrainVisArchitect;
21-
import org.openmolecules.render.TorsionStrainVisBuilder;
22-
import org.openmolecules.render.TorsionStrainVisualization;
16+
import org.openmolecules.render.*;
2317

2418
import java.util.HashMap;
2519
import java.util.Map;
@@ -51,14 +45,13 @@ public V3DMoleculeUpdater(V3DMolecule fxmol) {
5145
mPPNodeMap = new HashMap<PPGaussian,AbstractPPNode>();
5246
mVolNodeMap = new HashMap<VolumeGaussian,VolumeSphere>();
5347
for (Node node:fxmol.getChildren()) {
54-
int role = node.getUserData() == null ? 0 : ((NodeDetail)node.getUserData()).getRole();
55-
if ((role & (MoleculeBuilder.ROLE_IS_ATOM | MoleculeBuilder.ROLE_IS_BOND )) != 0)
56-
mNodeMap.put(role, node);
57-
else if( (role & MoleculeBuilder.ROLE_IS_TORSION_PREF)!=0)
58-
mNodeMap.put(role, node);
48+
NodeDetail detail = (NodeDetail)node.getUserData();
49+
if (detail != null
50+
&& (detail.isAtom() || detail.isBond() || detail.isTorsion())) {
51+
mNodeMap.put(detail.getRole(), node);
52+
}
5953
}
6054

61-
6255
for(V3DRotatableGroup group : fxmol.getGroups()) {
6356
if(group instanceof V3DCustomizablePheSA) {
6457
V3DCustomizablePheSA pharmacophore = (V3DCustomizablePheSA)group;
@@ -103,7 +96,7 @@ public void addAtomSphere(int role, Coordinates c, double radius, int argb) {
10396
node.setTranslateY(c.y);
10497
node.setTranslateZ(c.z);
10598

106-
if (mArchitect.getConstructionMode() == MoleculeArchitect.CONSTRUCTION_MODE_STICKS && (role & MoleculeBuilder.ROLE_IS_ATOM) != 0) {
99+
if (mArchitect.getConstructionMode() == MoleculeArchitect.CONSTRUCTION_MODE_STICKS && RoleHelper.isAtom(role)) {
107100
// update coordinates of transparent spheres
108101
node = mNodeMap.get(role | 0x80000000);
109102
if (node != null) {

src/main/java/org/openmolecules/fx/viewer3d/V3DMouseHandler.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.openmolecules.fx.viewer3d.nodes.NonRotatingLabel;
3939
import org.openmolecules.fx.viewer3d.nodes.VolumeSphere;
4040
import org.openmolecules.mesh.MoleculeSurfaceAlgorithm;
41-
import org.openmolecules.render.MoleculeBuilder;
4241
import org.openmolecules.render.TorsionHistogram;
4342

4443
import java.util.stream.IntStream;
@@ -320,10 +319,10 @@ private void trackHighlightedMol(MouseEvent me) {
320319

321320
mHighlightedMol = (V3DMolecule) molecule;
322321
if (mHighlightedMol != null && node instanceof Shape3D) {
323-
mHighlightedMol.setHighlightedShape((Shape3D)node);
324-
int role = node.getUserData() == null ? 0 : ((NodeDetail)node.getUserData()).getRole();
325-
if( (role & MoleculeBuilder.ROLE_IS_TORSION_PREF)!=0) {
326-
int b = ((NodeDetail)node.getUserData()).getBondTorsion();
322+
mHighlightedMol.setHighlightedShape((Shape3D)node);
323+
NodeDetail detail = (NodeDetail)node.getUserData();
324+
if (detail.isTorsion()) {
325+
int b = detail.getTorsion();
327326
byte[] histogram = mHighlightedMol.getTorsionStrainVis().getTorsionAnalyzer().getHistogram(b);
328327
if(histogram!=null) {
329328
double angle = mHighlightedMol.getTorsionStrainVis().getTorsionAnalyzer().getAngle(b);

0 commit comments

Comments
 (0)