From 63f777125b15fb6962ffef4350c851b925a7ebd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= <targos@protonmail.com> Date: Tue, 29 Oct 2024 08:52:55 +0100 Subject: [PATCH] feat: update OCL to v2024.10.2 (#237) --- openchemlib | 2 +- .../com/actelion/research/chem/Canonizer.java | 33 ++-- .../research/chem/ExtendedMolecule.java | 28 ++- .../research/chem/IsomericSmilesCreator.java | 2 +- .../actelion/research/chem/SSSearcher.java | 8 + .../descriptor/DescriptorWeightsHelper.java | 2 +- .../chem/shredder/FragmentGeometry3D.java | 27 ++- .../research/chem/shredder/Fragmenter3D.java | 2 +- .../editor/BondQueryFeatureDialogBuilder.java | 9 +- .../gui/editor/GenericEditorArea.java | 159 ++++++++++-------- 10 files changed, 164 insertions(+), 108 deletions(-) diff --git a/openchemlib b/openchemlib index e30c9f88..6cb49c86 160000 --- a/openchemlib +++ b/openchemlib @@ -1 +1 @@ -Subproject commit e30c9f88bb90c9b1ee688c121ee8ecfb2cc043c4 +Subproject commit 6cb49c868a3e03c6b91343be10cb80279112077c diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java index 56f5d038..6beda750 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java @@ -170,12 +170,12 @@ public class Canonizer { private boolean[] mNitrogenQualifiesForParity; private ArrayList<CanonizerFragment> mFragmentList; private ArrayList<int[]> mTHParityNormalizationGroupList; - private int mMode,mNoOfRanks,mNoOfPseudoGroups; + private final int mMode; + private int mNoOfRanks,mNoOfPseudoGroups; private boolean mIsOddParityRound; - private boolean mZCoordinatesAvailable,mAllHydrogensAreExplicit; + private final boolean mZCoordinatesAvailable,mAllHydrogensAreExplicit; private boolean mCIPParityNoDistinctionProblem; private boolean mEncodeAvoid127; - private boolean mGraphGenerated; private int mGraphRings,mFeatureBlock; private int[] mGraphAtom; @@ -184,9 +184,10 @@ public class Canonizer { private int[] mGraphFrom; private int[] mGraphClosure; - private String mIDCode, mEncodedCoords,mMapping; - private StringBuilder mEncodingBuffer; - private int mEncodingBitsAvail,mEncodingTempData,mAtomBits,mMaxConnAtoms; + private String mIDCode, mEncodedCoords,mMapping; + private StringBuilder mEncodingBuffer; + private int mEncodingBitsAvail,mEncodingTempData,mMaxConnAtoms; + private final int mAtomBits; /** * Runs a canonicalization procedure for the given molecule that creates unique atom ranks, @@ -204,7 +205,7 @@ public Canonizer(StereoMolecule mol) { * If mode includes ENCODE_ATOM_CUSTOM_LABELS, than custom atom labels are * considered for the atom ranking and are encoded into the idcode.<br> * If mode includes COORDS_ARE_3D, then getEncodedCoordinates() always returns - * a 3D-encoding even if all z-coordinates are 0.0. Otherwise coordinates are + * a 3D-encoding even if all z-coordinates are 0.0. Otherwise, coordinates are * encoded in 3D only, if at least one of the z-coords is not 0.0. * @param mol * @param mode 0 or one or more of CONSIDER...TOPICITY, CREATE..., ENCODE_ATOM_CUSTOM_LABELS, ASSIGN_PARITIES_TO_TETRAHEDRAL_N, COORDS_ARE_3D @@ -226,17 +227,7 @@ public Canonizer(StereoMolecule mol, int mode) { mZCoordinatesAvailable = ((mode & COORDS_ARE_3D) != 0) || mMol.is3D(); - mAllHydrogensAreExplicit = false; - if (mMol.getAllAtoms() > mMol.getAtoms() - && !mMol.isFragment()) { - mAllHydrogensAreExplicit = true; - for (int i=0; i<mMol.getAtoms(); i++) { - if (mMol.getImplicitHydrogens(i) != 0) { - mAllHydrogensAreExplicit = false; - break; - } - } - } + mAllHydrogensAreExplicit = (mMol.getImplicitHydrogens() == 0); if ((mMode & NEGLECT_ANY_STEREO_INFORMATION) == 0) { mTHParity = new byte[mMol.getAtoms()]; @@ -639,7 +630,7 @@ private boolean canInnerBreakTiesByHeteroTopicity() { private void canBreakTiesRandomly() { for (int atom=0; atom<mMol.getAtoms(); atom++) { mCanBase[atom].init(atom); - mCanBase[atom].add(mAtomBits+1, 2*mCanRank[atom]); + mCanBase[atom].add(mAtomBits+1, (long)2*mCanRank[atom]); } // promote randomly one atom of lowest shared rank. @@ -895,7 +886,7 @@ private void canRecursivelyFindAllParities() { thParityInfo |= mTHESRGroup[atom]; } - mCanBase[atom].add(2 * parityInfoBits, thParityInfo << parityInfoBits); // generate space for bond parity + mCanBase[atom].add(2 * parityInfoBits, (long)thParityInfo << parityInfoBits); // generate space for bond parity } for (int bond=0; bond<mMol.getBonds(); bond++) { @@ -3371,7 +3362,7 @@ public String getEncodedCoordinates() { * original molecule including coordinates.<br> * If keepPositionAndScale==false, then coordinate encoding will be relative, * i.e. scale and absolute positions get lost during the encoding. - * Otherwise the encoding retains scale and absolute positions.<br> + * Otherwise, the encoding retains scale and absolute positions.<br> * If the molecule has 3D-coordinates and if there are no implicit hydrogen atoms, * i.e. all hydrogen atoms are explicitly available with their coordinates, then * hydrogen 3D-coordinates are also encoded despite the fact that the idcode itself does diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMolecule.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMolecule.java index db7c7ae1..b901fdba 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMolecule.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMolecule.java @@ -1445,7 +1445,28 @@ public boolean supportsImplicitHydrogen(int atom) { } /** - * Calculates and return the number of implicit hydrogens at atom. + * Calculates and returns the number of implicit hydrogens of the molecule. + * For hydrogens atoms, metals except Al, or a noble gases, 0 is assumed. + * For all other atom kinds the number of implicit hydrogens is basically + * the lowest typical valence that is compatible with the occupied valence, + * minus the occupied valence corrected by atom charge and radical state. + * If this molecule is a fragment, then 0 is returned. + * @return number of implicit hydrogens of the molecule + */ + public int getImplicitHydrogens() { + if (mIsFragment) + return 0; + + ensureHelperArrays(cHelperNeighbours); + int implicitHydrogens = 0; + for (int atom=0; atom<mAtoms; atom++) + implicitHydrogens += getImplicitHydrogens(atom); + + return implicitHydrogens; + } + + /** + * Calculates and returns the number of implicit hydrogens at atom. * If atom is itself a hydrogen atom, a metal except Al, or a noble gas, * then 0 is returned. For all other atom kinds the number of * implicit hydrogens is basically the lowest typical valence that is compatible @@ -1463,8 +1484,9 @@ public int getImplicitHydrogens(int atom) { if (!supportsImplicitHydrogen(atom)) return 0; - if ("*".equals(getAtomCustomLabel(atom))) - return 0; + // attachment points have at least a valence of 1, i.e. they must be connected to something + if (mAtomicNo[atom] == 0 || "*".equals(getAtomCustomLabel(atom))) + return mAllConnAtoms[atom] == 0 ? 1 : 0; ensureHelperArrays(cHelperNeighbours); diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IsomericSmilesCreator.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IsomericSmilesCreator.java index f282b1d0..d6e9d2bc 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IsomericSmilesCreator.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IsomericSmilesCreator.java @@ -820,7 +820,7 @@ private void appendBondOrderSymbol(int bond, int parentAtom, StringBuilder build if (mEZHalfParity[bond] != 0) builder.append(mEZHalfParity[bond] == 1 ? '/' : '\\'); if (mMode == MODE_CREATE_SMARTS) { - int bondTypes = mMol.getBondQueryFeatures(Molecule.cBondQFBondTypes | Molecule.cBondQFRareBondTypes); + int bondTypes = mMol.getBondQueryFeatures(bond) & (Molecule.cBondQFBondTypes | Molecule.cBondQFRareBondTypes); if (bondTypes != 0) { if ((bondTypes & Molecule.cBondTypeSingle) != 0 && mEZHalfParity[bond] == 0) { builder.append('-'); diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/SSSearcher.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/SSSearcher.java index ed8af926..c7fcc73a 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/SSSearcher.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/SSSearcher.java @@ -1322,6 +1322,14 @@ public boolean areBondsSimilar(int moleculeBond, int fragmentBond) { && ringSize == (mMolecule.getBondQueryFeatures(fragmentBond) & Molecule.cBondQFRingSize) >> Molecule.cBondQFRingSizeShift) return true; + if (ringSize <= 2) { // ring size 8-11 is encoded as 1; ring size >=12 is encoded as 2 + int moleculeRingSize = mMolecule.getBondRingSize(moleculeBond); + if (ringSize == 1) + return (moleculeRingSize >= 8) && (moleculeRingSize <= 12); + else + return moleculeRingSize >= 12; + } + boolean found = false; RingCollection ringSet = mMolecule.getRingSet(); for (int i=0; i<ringSet.getSize(); i++) { diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java index 2d8148fb..b9e6dd68 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java @@ -71,7 +71,7 @@ public DescriptorWeightsHelper() { * - Charged pp points are set mandatory. * @param liSubGraphIndices * @param molecule3D - * @return + * @return array with dimension molecule3D.getAtoms(). */ public static int [] calcWeightLabels(List<SubGraphIndices> liSubGraphIndices, Molecule3D molecule3D){ diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java index 0a7eb563..986419c8 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java @@ -74,7 +74,7 @@ private Coordinates[] determineAlignmentCoords() { coords[i] = mMol.getCoordinates(mExitVector[i].rootAtom); coords[mExitVector.length + i] = mMol.getCoordinates(mExitVector[i].exitAtom); - // for lonely hydrogens (selected H connects to other exit atom) + // for lonely hydrogens (single selected H connecting to non-selected exit atom) // we need to place the root coord (hydrogen) further away from the exit atom, // to reflect the longer bond length of a C-C compared to H-C if (mMol.getAtomicNo(mExitVector[i].rootAtom) == 1) @@ -123,9 +123,10 @@ public boolean equals(FragmentGeometry3D geometry) { * is returned. * @param geometry the geometry to be aligned with this * @param permutation permutation index for equivalent root atoms of the passed geometry + * @param rmsdHolder null or double[1] to receive RMSD value * @return rotation matrix or null, depending on whether alignment is acceptable */ - public double[][] alignRootAndExitAtoms(FragmentGeometry3D geometry, int permutation, double maxRMSD) { + public double[][] alignRootAndExitAtoms(FragmentGeometry3D geometry, int permutation, double[] rmsdHolder, double maxRMSD) { ExitVector[] geomEV = geometry.mExitVector; Coordinates[] coords = new Coordinates[2*geomEV.length]; for (int i=0; i<geomEV.length; i++) @@ -141,19 +142,27 @@ public double[][] alignRootAndExitAtoms(FragmentGeometry3D geometry, int permuta c.add(mAlignmentCOG); } - return Coordinates.getRmsd(mAlignmentCoords, coords) > maxRMSD ? null : matrix; + double rmsd = Coordinates.getRmsd(mAlignmentCoords, coords); + if (rmsdHolder != null) + rmsdHolder[0] = rmsd; + + return rmsd > maxRMSD ? null : matrix; } - public boolean hasMatchingExitVectors(FragmentGeometry3D geometry, Coordinates[] coords, int permutation, double maxAngleDivergence) { - maxAngleDivergence *= Math.PI / 180; - for (int i = 0; i<mExitVector.length; i++) { + public boolean hasMatchingExitVectors(FragmentGeometry3D geometry, Coordinates[] coords, int permutation, double[][] angleHolder, double maxAngleDivergence) { + double[] angleDif = new double[mExitVector.length]; + boolean qualifies = true; + for (int i=0; i<mExitVector.length; i++) { Coordinates v1 = mAlignmentCoords[mExitVector.length+i].subC(mAlignmentCoords[i]); ExitVector ev2 = geometry.mExitVector[mPermutation[permutation][i]]; Coordinates v2 = coords[ev2.exitAtom].subC(coords[ev2.rootAtom]); - if (v1.getAngle(v2) > maxAngleDivergence) - return false; + angleDif[i] = v1.getAngle(v2) * 180 / Math.PI; + if (angleDif[i] > maxAngleDivergence) + qualifies = false; } - return true; + if (angleHolder != null) + angleHolder[0] = angleDif; + return qualifies; } public int getPermutationCount() { diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java index 89d76417..409450d0 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java @@ -55,7 +55,7 @@ public ArrayList<Fragment3D> buildFragments(StereoMolecule mol, boolean withHydr int fragmentCount = mol.getFragmentNumbers(fragmentNo, isRotatableBond, true); int[] atomCount = new int[fragmentCount]; - for (int atom=0; atom<mol.getAllAtoms(); atom++) + for (int atom=0; atom<mol.getAtoms(); atom++) atomCount[fragmentNo[atom]]++; BaseFragmentInfo[] fragmentData = new BaseFragmentInfo[fragmentCount]; diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/BondQueryFeatureDialogBuilder.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/BondQueryFeatureDialogBuilder.java index 27dd4560..57731b63 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/BondQueryFeatureDialogBuilder.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/BondQueryFeatureDialogBuilder.java @@ -116,6 +116,8 @@ private void build(ExtendedMolecule mol, int bond) { mComboBoxRingSize.addItem("is in 5-membered ring"); mComboBoxRingSize.addItem("is in 6-membered ring"); mComboBoxRingSize.addItem("is in 7-membered ring"); + mComboBoxRingSize.addItem("smallest ring 8 to 11"); + mComboBoxRingSize.addItem("smallest ring >= 12"); mDialog.add(mComboBoxRingSize, 1,13,3,13); mCBMatchFormalOrder = mDialog.createCheckBox("Match formal bond order"); @@ -223,7 +225,7 @@ else if (aromState == Molecule.cBondQFNotAromatic) mComboBoxRing.setSelectedIndex(0); int ringSize = (queryFeatures & Molecule.cBondQFRingSize) >> Molecule.cBondQFRingSizeShift; - mComboBoxRingSize.setSelectedIndex((ringSize == 0) ? 0 : ringSize-2); + mComboBoxRingSize.setSelectedIndex((ringSize == 0) ? 0 : (ringSize <= 2) ? ringSize+5 : ringSize-2); if ((queryFeatures & Molecule.cBondQFBridge) != 0) { mCBIsBridge.setSelected(true); @@ -361,9 +363,12 @@ else if (mComboBoxRing.getSelectedIndex() == 4) { if (mComboBoxRingSize.getSelectedIndex() != 0) { int ringSize = mComboBoxRingSize.getSelectedIndex() + 2; + if (ringSize > 7) // ringsize 8-11 is encoded as 1; ringsize >12 is encoded as 2 + ringSize -= 7; int implicitSize = mMol.getBondRingSize(bond); - if (ringSize != implicitSize) + if (ringSize <= 2 || ringSize != implicitSize) { // options 1 and 2 cover spans and cannot be implicit queryFeatures |= (ringSize << Molecule.cBondQFRingSizeShift); + } } } diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/GenericEditorArea.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/GenericEditorArea.java index 3e81c7d8..6299313b 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/GenericEditorArea.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/gui/editor/GenericEditorArea.java @@ -985,75 +985,8 @@ private void eventHappened(GenericMouseEvent e) { switch (mPendingRequest) { case cRequestNewChain: - double lastX, lastY; - if (mChainAtoms>0) { - lastX = mChainAtomX[mChainAtoms - 1]; - lastY = mChainAtomY[mChainAtoms - 1]; - } else { - lastX = 0; - lastY = 0; - } - double avbl = getScaledAVBL(); - double s0 = (int)avbl; - double s1 = (int)(0.866 * avbl); - double s2 = (int)(0.5 * avbl); - double dx = mX2 - mX1; - double dy = mY2 - mY1; - if (Math.abs(dy)>Math.abs(dx)) { - mChainAtoms = (int)(2 * Math.abs(dy) / (s0 + s2)); - if (Math.abs(dy) % (s0 + s2)>s0) { - mChainAtoms++; - } - mChainAtomX = new double[mChainAtoms]; - mChainAtomY = new double[mChainAtoms]; - if (mX2<mX1) { - s1 = -s1; - } - if (mY2<mY1) { - s0 = -s0; - s2 = -s2; - } - for (int i = 0; i<mChainAtoms; i++) { - mChainAtomX[i] = mX1 + 0.5 * (i + 1) * s1; - mChainAtomY[i] = mY1 + 0.5 * (i + 1) * (s0 + s2); - if ((i & 1) == 0) { - mChainAtomY[i] += s0; - } - } - } else { - mChainAtoms = (int)(Math.abs(dx) / s1); - mChainAtomX = new double[mChainAtoms]; - mChainAtomY = new double[mChainAtoms]; - if (mX2<mX1) { - s1 = -s1; - } - if (mY2<mY1) { - s2 = -s2; - } - for (int i = 0; i<mChainAtoms; i++) { - mChainAtomX[i] = mX1 + (i + 1) * s1; - mChainAtomY[i] = mY1; - if ((i & 1) == 0) { - mChainAtomY[i] += s2; - } - } - } - if (mChainAtoms>0) { - mChainAtom = new int[mChainAtoms]; - for (int i = 0; i<mChainAtoms; i++) { - mChainAtom[i] = mMol.findAtom(mChainAtomX[i], mChainAtomY[i]); - if (mChainAtom[i] != -1) { - mChainAtomX[i] = mMol.getAtomX(mChainAtom[i]); - mChainAtomY[i] = mMol.getAtomY(mChainAtom[i]); - } - } - if (mChainAtomX[mChainAtoms - 1] != lastX - || mChainAtomY[mChainAtoms - 1] != lastY) { - repaintNeeded = true; - } - } else if (lastX != 0 || lastY != 0) { + if (suggestNewChain()) repaintNeeded = true; - } break; case cRequestNewBond: if ((mX2 - mX1) * (mX2 - mX1) + (mY2 - mY1) * (mY2 - mY1)<MIN_BOND_LENGTH_SQUARE) { @@ -1173,6 +1106,94 @@ private void eventHappened(GenericMouseEvent e) { } } + private boolean suggestNewChain() { + double mouseAngle = Molecule.getAngle(mX1, mY1, mX2, mY2); + + double mdx = mX2 - mX1; + double mdy = mY2 - mY1; + + int lastChainAtoms = mChainAtoms; + int lastX1 = 0; + int lastY1 = 0; + int lastX2 = 0; + int lastY2 = 0; + if (lastChainAtoms > 0) { + lastX1 = (int)Math.round(mChainAtomX[0]); + lastY1 = (int)Math.round(mChainAtomY[0]); + } + if (lastChainAtoms > 1) { + lastX2 = (int)Math.round(mChainAtomX[1]); + lastY2 = (int)Math.round(mChainAtomY[1]); + } + + double exitAngle = 0; + if (mAtom1 == -1 || mMol.getAllConnAtomsPlusMetalBonds(mAtom1) == 0) { + exitAngle = Math.PI / 3 * Math.round(mouseAngle * 3 / Math.PI); + } + else if (mMol.getAllConnAtomsPlusMetalBonds(mAtom1) == 1) { + double bondAngle = mMol.getBondAngle(mMol.getConnAtom(mAtom1, 0), mAtom1); + double candidate1 = bondAngle - Math.PI / 3; + double candidate2 = bondAngle + Math.PI / 3; + exitAngle = Math.abs(Molecule.getAngleDif(mouseAngle, candidate1)) + < Math.abs(Molecule.getAngleDif(mouseAngle, candidate2)) ? candidate1 : candidate2; + } + else { + double[] connAngle = new double[mMol.getAllConnAtomsPlusMetalBonds(mAtom1)]; + for (int i=0; i<mMol.getAllConnAtomsPlusMetalBonds(mAtom1); i++) + connAngle[i] = mMol.getBondAngle(mAtom1, mMol.getConnAtom(mAtom1, i)); + + Arrays.sort(connAngle); + for (int i=0; i<connAngle.length; i++) { + double leftAngle = (i == 0) ? connAngle[connAngle.length-1] - 2.0*Math.PI : connAngle[i-1]; + if (leftAngle < mouseAngle && mouseAngle < connAngle[i]) { + exitAngle = (connAngle[i] + leftAngle) / 2.0; + break; + } + if (leftAngle < mouseAngle - 2.0 * Math.PI && mouseAngle - 2.0 * Math.PI < connAngle[i]) { + exitAngle = (connAngle[i] + leftAngle) / 2.0; + break; + } + } + } + + double avbl = getScaledAVBL(); + mChainAtoms = Math.abs(Molecule.getAngleDif(mouseAngle, exitAngle)) > Math.PI / 3 ? 0 : (int)(Math.sqrt(mdx*mdx + mdy*mdy) / avbl); + if (mChainAtoms > 0) { + if (mChainAtomX == null || mChainAtomX.length < mChainAtoms) { + mChainAtomX = new double[mChainAtoms]; + mChainAtomY = new double[mChainAtoms]; + } + double[] dx = new double[2]; + double[] dy = new double[2]; + double nextAngle = Molecule.getAngleDif(mouseAngle, exitAngle) < 0 ? exitAngle - Math.PI / 3 : exitAngle + Math.PI / 3; + dx[0] = avbl * Math.sin(exitAngle); + dy[0] = avbl * Math.cos(exitAngle); + dx[1] = avbl * Math.sin(nextAngle); + dy[1] = avbl * Math.cos(nextAngle); + for (int i=0; i<mChainAtoms; i++) { + mChainAtomX[i] = (i == 0 ? mX1 : mChainAtomX[i-1]) + dx[i & 1]; + mChainAtomY[i] = (i == 0 ? mY1 : mChainAtomY[i-1]) + dy[i & 1]; + } + + mChainAtom = new int[mChainAtoms]; + for (int i = 0; i<mChainAtoms; i++) { + mChainAtom[i] = mMol.findAtom(mChainAtomX[i], mChainAtomY[i]); + if (mChainAtom[i] != -1) { + mChainAtomX[i] = mMol.getAtomX(mChainAtom[i]); + mChainAtomY[i] = mMol.getAtomY(mChainAtom[i]); + } + } + } + + return lastChainAtoms != mChainAtoms + || ((mChainAtoms != 0) + && (lastX1 != (int)Math.round(mChainAtomX[0]) + || lastY1 != (int)Math.round(mChainAtomY[0]))) + || ((mChainAtoms > 1) + && (lastX2 != (int)Math.round(mChainAtomX[1]) + || lastY2 != (int)Math.round(mChainAtomY[1]))); + } + public void showHelpDialog() { mUIHelper.showHelpDialog("/html/editor/editor.html", "Structure Editor Help"); } @@ -2369,7 +2390,7 @@ private void suggestNewX2AndY2(int atom) { double newAngle = Math.PI * 2 / 3; if (atom != -1) { - double angle[] = new double[MAX_CONNATOMS + 1]; + double[] angle = new double[MAX_CONNATOMS + 1]; for (int i = 0; i<mMol.getAllConnAtomsPlusMetalBonds(atom); i++) { angle[i] = mMol.getBondAngle(atom, mMol.getConnAtom(atom, i)); }