User 870ab5b546
31-01-2017 19:46:45
Here is some code that creates a button in MarvinSketch that allows you to select two, three, or four atoms to measure an atom-atom distance, a bond angle, or a dihedral angle about a bond, respectively.
In the code that invokes MarvinSketch, inside the then() block, add:
// measure length/angle/dihedral button
buttonAttrs = {
'name' : 'measure length/angle/dihedral',
'image-url' : '/webApp/images/ruler.png', // button icon
'toolbar' : 'S'
};
marvinSketcherInstance.addButton(buttonAttrs, function() {
marvinSketcherInstance.exportStructure('mrv').then(function(mol) {
targetPage = '/webApp/includes/measure.jsp';
// target page name must be exactly the same as in openwindows.js
newForm = prepareForm(targetPage, 'Measure');
newForm.appendChild(prepareField('mrvStr', mol));
newForm.appendChild(prepareField('selectedAtomsStr',
marvinSketcherInstance.getSelection().atoms));
document.body.appendChild(newForm); // necessary for Firefox
openMeasureWindow(targetPage);
newForm.submit();
}, function(error) {
alert('Molecule export to MRV failed: ' + error);
});
});
(The icon that I created, images/ruler.jsp, is attached below.) Make these Javascript methods available as well:
/* Makes a new form that will invoke the given target page in a target
* window with the given name. */
function prepareForm(targetPage, targetPageName) {
"use strict";
var newForm = document.createElement('form');
newForm.setAttribute('method', 'post');
newForm.setAttribute('action', targetPage);
// target name must be exactly the same as in openwindows.js
newForm.setAttribute('target', targetPageName);
return newForm;
} // prepareForm()
// Measure distance/angle/dihedral window
function openMeasureWindow(url) {
"use strict";
var w = window.open(url, 'Measure',
'width=400,height=200,left=200,top=70,resizable=yes,scrollbars=yes,status=yes');
w.focus();
}
Finally, the contents of measure.jsp, the page that actually does the calculations and displays them:
<%@ page language="java" %>
<%@ page import="
chemaxon.formats.MolImporter,
chemaxon.struc.MolAtom,
chemaxon.struc.Molecule,
chemaxon.marvin.calculations.GeometryPlugin,
java.text.NumberFormat,
java.util.ArrayList,
java.util.List"
%>
<%
final String pathToRoot = "../";
final String mrvStr = request.getParameter("mrvStr");
final String selectedAtomsStr = request.getParameter("selectedAtomsStr");
boolean doCalculation = true;
Molecule molecule = null;
final GeometryPlugin calculator = new GeometryPlugin();
if (mrvStr != null && !"".equals(mrvStr)) {
molecule = MolImporter.importMol(mrvStr);
calculator.setMolecule(molecule);
} else doCalculation = false;
int numAtoms = 0;
double geomValue = 0.0;
if (selectedAtomsStr != null && !"".equals(selectedAtomsStr) && doCalculation) {
final String[] atomIndexStrs = selectedAtomsStr.split(",");
numAtoms = atomIndexStrs.length;
final int[] atomIndices = new int[numAtoms];
for (int j = 0; j < numAtoms; j++) {
atomIndices[j] = Integer.parseInt(atomIndexStrs[j]) - 1;
} // for each atom
if (numAtoms == 2) {
geomValue = calculator.getDistance(atomIndices);
} else if (numAtoms == 3) {
final List<MolAtom> atoms = new ArrayList<MolAtom>();
for (int atomIndexNum = 0; atomIndexNum < 3; atomIndexNum++) {
atoms.add(molecule.getAtom(atomIndices[atomIndexNum]));
} // for each atom index
doCalculation = false;
for (int atomIndexNum = 0; atomIndexNum < 3; atomIndexNum++) {
if (atoms.get(1).getBondTo(atoms.get(0)) != null
&& atoms.get(1).getBondTo(atoms.get(2)) != null) {
doCalculation = true;
break;
}
atoms.add(atoms.remove(0));
} // for each atom index
for (int atomIndexNum = 0; atomIndexNum < 3; atomIndexNum++) {
atomIndices[atomIndexNum] = molecule.indexOf(atoms.get(atomIndexNum));
} // for each atom
geomValue = calculator.getAngle(atomIndices);
} else if (numAtoms == 4) {
final MolAtom[] atoms = new MolAtom[4];
for (int atomIndexNum = 0; atomIndexNum < 4; atomIndexNum++) {
atoms[atomIndexNum] = molecule.getAtom(atomIndices[atomIndexNum]);
} // for each atom index
// sort the two middle atoms from the two outside atoms
final int[] atomNumsOrdered = new int[] {-1, -1, -1, -1};
for (int atomIndex : atomIndices) {
final MolAtom refAtom = molecule.getAtom(atomIndex);
if (getNumBonded(atoms, refAtom) == 2) {
if (atomNumsOrdered[1] == -1) atomNumsOrdered[1] = atomIndex;
else atomNumsOrdered[2] = atomIndex;
} else {
if (atomNumsOrdered[0] == -1) atomNumsOrdered[0] = atomIndex;
else atomNumsOrdered[3] = atomIndex;
} // if atom is bonded to 1 or 2 other atoms
} // for each atom
if (atomNumsOrdered[1] == -1 || atomNumsOrdered[2] == -1) {
doCalculation = false;
} else {
// now it's either A-B-C-D or D-B-C-A
if (molecule.getAtom(atomNumsOrdered[0]).getBondTo(
molecule.getAtom(atomNumsOrdered[1])) == null) {
final int dummy = atomNumsOrdered[0];
atomNumsOrdered[0] = atomNumsOrdered[3];
atomNumsOrdered[3] = dummy;
} // if atom0 not bonded to atom1
geomValue = calculator.getDihedral(atomNumsOrdered);
} // if there is a central bond
} else doCalculation = false; // not 2-4 atoms entered
} else doCalculation = false; // no atoms entered
final NumberFormat numberFormat = NumberFormat.getInstance();
numberFormat.setMaximumFractionDigits(numAtoms == 2 ? 2 : 1);
numberFormat.setMinimumFractionDigits(numAtoms == 2 ? 2 : 1);
final String valueStr = numberFormat.format(geomValue)
+ (numAtoms == 2 ? " angstroms" : " degrees"));
%>
<%!
static int getNumBonded(MolAtom[] atoms, MolAtom refAtom) {
int numBonds = 0;
for (final MolAtom atom : atoms) {
if (atom != refAtom && atom.getBondTo(refAtom) != null) numBonds++;
} // for each atom
return numBonds;
} // getNumBonded(MolAtom[], MolAtom)
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Measure distance/angle/dihedral</title>
<script src="<%= pathToRoot %>js/jslib.js" type="text/javascript"></script>
<script type="text/javascript">
// <!-- >
function showMeasurement() {
if (<%= doCalculation %>) {
alert('The value of the <%=
numAtoms == 2 ? "distance between the atoms"
: numAtoms == 3 ? "bond angle"
: "dihedral angle" %> is <%= valueStr %>.');
} else {
alert('Invalid selection. Draw or paste a 3D '
+ 'structure, and highlight two atoms to get their distance, '
+ 'three contiguous atoms to get their angle, or four '
+ 'contiguous atoms to get their dihedral angle.');
}
self.close();
} // showMeasurement()
// -->
</script>
</head>
<body onload="showMeasurement();">
</body>
</html>
Much of the code for the dihedral angle and angle measurements is to place the atoms in the correct order for the geometry plugin.