1 /* $RCSfiodelle$allrueFFFF 2 * $Author: egonw $ 3 * $Date: 2005-11-10 09:52:44 -0600 (Thu, 10 Nov 2005) $ 4 * $Revision: 4255 $ 5 * 6 * Copyright (C) 2003-2005 Miguel, Jmol Development, www.jmol.org 7 * 8 * Contact: jmol-developers@lists.sf.net 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 25 package org.jmol.symmetry; 26 27 import java.util.Map; 28 29 import org.jmol.api.AtomIndexIterator; 30 import org.jmol.api.GenericPlatform; 31 import org.jmol.api.Interface; 32 import org.jmol.api.SymmetryInterface; 33 import org.jmol.bspt.Bspt; 34 import org.jmol.bspt.CubeIterator; 35 import org.jmol.modelset.Atom; 36 import org.jmol.modelset.ModelSet; 37 import org.jmol.script.T; 38 import org.jmol.util.Escape; 39 import org.jmol.util.JmolMolecule; 40 import org.jmol.util.Logger; 41 import org.jmol.util.SimpleUnitCell; 42 import org.jmol.util.Tensor; 43 import org.jmol.viewer.Viewer; 44 45 import javajs.util.BS; 46 import javajs.util.Lst; 47 import javajs.util.M3; 48 import javajs.util.M4; 49 import javajs.util.Matrix; 50 import javajs.util.P3; 51 import javajs.util.Quat; 52 import javajs.util.SB; 53 import javajs.util.T3; 54 import javajs.util.V3; 55 56 public class Symmetry implements SymmetryInterface { 57 // NOTE: THIS CLASS IS VERY IMPORTANT. 58 // IN ORDER TO MODULARIZE IT, IT IS REFERENCED USING 59 // xxxx = Interface.getSymmetry(); 60 61 /* Symmetry is a wrapper class that allows access to the package-local 62 * classes PointGroup, SpaceGroup, SymmetryInfo, and UnitCell. 63 * 64 * When symmetry is detected in ANY model being loaded, a SymmetryInterface 65 * is established for ALL models. 66 * 67 * The SpaceGroup information could be saved with each model, but because this 68 * depends closely on what atoms have been selected, and since tracking that with atom 69 * deletion is a bit complicated, instead we just use local instances of that class. 70 * 71 * The three PointGroup methods here could be their own interface; they are just here 72 * for convenience. 73 * 74 * The file readers use SpaceGroup and UnitCell methods 75 * 76 * The modelSet and modelLoader classes use UnitCell and SymmetryInfo 77 * 78 */ 79 private PointGroup pointGroup; 80 SpaceGroup spaceGroup; 81 private SymmetryInfo symmetryInfo; 82 private UnitCell unitCell; 83 private boolean isBio; 84 85 @Override isBio()86 public boolean isBio() { 87 return isBio; 88 } 89 Symmetry()90 public Symmetry() { 91 // instantiated ONLY using 92 // symmetry = Interface.getSymmetry(); 93 // DO NOT use symmetry = new Symmetry(); 94 // as that will invalidate the Jar file modularization 95 } 96 97 @Override setPointGroup(SymmetryInterface siLast, T3 center, T3[] atomset, BS bsAtoms, boolean haveVibration, float distanceTolerance, float linearTolerance, boolean localEnvOnly)98 public SymmetryInterface setPointGroup(SymmetryInterface siLast, 99 T3 center, T3[] atomset, 100 BS bsAtoms, 101 boolean haveVibration, 102 float distanceTolerance, 103 float linearTolerance, boolean localEnvOnly) { 104 pointGroup = PointGroup.getPointGroup(siLast == null ? null 105 : ((Symmetry) siLast).pointGroup, center, atomset, bsAtoms, 106 haveVibration, distanceTolerance, linearTolerance, localEnvOnly); 107 return this; 108 } 109 110 @Override getPointGroupName()111 public String getPointGroupName() { 112 return pointGroup.getName(); 113 } 114 115 @Override getPointGroupInfo(int modelIndex, String drawID, boolean asInfo, String type, int index, float scale)116 public Object getPointGroupInfo(int modelIndex, String drawID, 117 boolean asInfo, String type, int index, 118 float scale) { 119 if (drawID == null && !asInfo && pointGroup.textInfo != null) 120 return pointGroup.textInfo; 121 else if (drawID == null && pointGroup.isDrawType(type, index, scale)) 122 return pointGroup.drawInfo; 123 else if (asInfo && pointGroup.info != null) 124 return pointGroup.info; 125 return pointGroup.getInfo(modelIndex, drawID, asInfo, type, index, scale); 126 } 127 128 // SpaceGroup methods 129 130 @Override setSpaceGroup(boolean doNormalize)131 public void setSpaceGroup(boolean doNormalize) { 132 if (spaceGroup == null) 133 spaceGroup = SpaceGroup.getNull(true, doNormalize, false); 134 } 135 136 @Override addSpaceGroupOperation(String xyz, int opId)137 public int addSpaceGroupOperation(String xyz, int opId) { 138 return spaceGroup.addSymmetry(xyz, opId, false); 139 } 140 141 @Override addBioMoleculeOperation(M4 mat, boolean isReverse)142 public int addBioMoleculeOperation(M4 mat, boolean isReverse) { 143 isBio = spaceGroup.isBio = true; 144 return spaceGroup.addSymmetry((isReverse ? "!" : "") + "[[bio" + mat, 0, 145 false); 146 } 147 148 @Override setLattice(int latt)149 public void setLattice(int latt) { 150 spaceGroup.setLatticeParam(latt); 151 } 152 153 @Override getSpaceGroup()154 public Object getSpaceGroup() { 155 return spaceGroup; 156 } 157 158 @Override setSpaceGroupFrom(SymmetryInterface symmetry)159 public void setSpaceGroupFrom(SymmetryInterface symmetry) { 160 spaceGroup = (SpaceGroup) symmetry.getSpaceGroup(); 161 } 162 163 /** 164 * 165 * @param desiredSpaceGroupIndex 166 * @param name 167 * @param data a Lst<SymmetryOperation> or Lst<M4> 168 * @param modDim in [3+d] modulation dimension 169 * @return true if a known space group 170 */ 171 @Override createSpaceGroup(int desiredSpaceGroupIndex, String name, Object data, int modDim)172 public boolean createSpaceGroup(int desiredSpaceGroupIndex, String name, 173 Object data, int modDim) { 174 spaceGroup = SpaceGroup.createSpaceGroup(desiredSpaceGroupIndex, name, 175 data, modDim); 176 if (spaceGroup != null && Logger.debugging) 177 Logger.debug("using generated space group " + spaceGroup.dumpInfo()); 178 return spaceGroup != null; 179 } 180 181 @Override getSpaceGroupInfoObj(String name, SymmetryInterface cellInfo, boolean isFull)182 public Object getSpaceGroupInfoObj(String name, SymmetryInterface cellInfo, boolean isFull) { 183 return SpaceGroup.getInfo(spaceGroup, name, cellInfo, isFull); 184 } 185 186 @Override getLatticeDesignation()187 public Object getLatticeDesignation() { 188 return spaceGroup.getLatticeDesignation(); 189 } 190 191 @Override setFinalOperations(String name, P3[] atoms, int iAtomFirst, int noSymmetryCount, boolean doNormalize, String filterSymop)192 public void setFinalOperations(String name, P3[] atoms, int iAtomFirst, 193 int noSymmetryCount, boolean doNormalize, 194 String filterSymop) { 195 if (name != null && (name.startsWith("bio") || name.indexOf(" *(") >= 0)) // filter SYMOP 196 spaceGroup.name = name; 197 if (filterSymop != null) { 198 Lst<SymmetryOperation> lst = new Lst<SymmetryOperation>(); 199 lst.addLast(spaceGroup.operations[0]); 200 for (int i = 1; i < spaceGroup.operationCount; i++) 201 if (filterSymop.contains(" " + (i + 1) + " ")) 202 lst.addLast(spaceGroup.operations[i]); 203 spaceGroup = SpaceGroup.createSpaceGroup(-1, 204 name + " *(" + filterSymop.trim() + ")", lst, -1); 205 } 206 spaceGroup.setFinalOperations(atoms, iAtomFirst, noSymmetryCount, 207 doNormalize); 208 } 209 210 @Override getSpaceGroupOperation(int i)211 public M4 getSpaceGroupOperation(int i) { 212 return (spaceGroup == null || spaceGroup.operations == null // bio 213 || i >= spaceGroup.operations.length ? null 214 : spaceGroup.finalOperations == null ? spaceGroup.operations[i] 215 : spaceGroup.finalOperations[i]); 216 } 217 218 @Override getSpaceGroupOperationRaw(int i)219 public M4 getSpaceGroupOperationRaw(int i) { 220 return spaceGroup.getRawOperation(i); 221 } 222 223 @Override getSpaceGroupXyz(int i, boolean doNormalize)224 public String getSpaceGroupXyz(int i, boolean doNormalize) { 225 return spaceGroup.getXyz(i, doNormalize); 226 } 227 228 @Override newSpaceGroupPoint(int i, P3 atom1, P3 atom2, int transX, int transY, int transZ, M4 o)229 public void newSpaceGroupPoint(int i, P3 atom1, P3 atom2, int transX, 230 int transY, int transZ, M4 o) { 231 if (o == null && spaceGroup.finalOperations == null) { 232 SymmetryOperation op = spaceGroup.operations[i]; 233 // temporary spacegroups don't have to have finalOperations 234 if (!op.isFinalized) 235 op.doFinalize(); 236 SymmetryOperation.newPoint(op, atom1, atom2, transX, transY, transZ); 237 return; 238 } 239 SymmetryOperation.newPoint((o == null ? spaceGroup.finalOperations[i] : o), atom1, atom2, transX, transY, transZ); 240 } 241 242 @Override rotateAxes(int iop, V3[] axes, P3 ptTemp, M3 mTemp)243 public V3[] rotateAxes(int iop, V3[] axes, P3 ptTemp, M3 mTemp) { 244 return (iop == 0 ? axes : spaceGroup.finalOperations[iop].rotateAxes(axes, 245 unitCell, ptTemp, mTemp)); 246 } 247 248 @Override getSpaceGroupOperationCode(int iOp)249 public String getSpaceGroupOperationCode(int iOp) { 250 return spaceGroup.operations[iOp].subsystemCode; 251 } 252 253 @Override setTimeReversal(int op, int val)254 public void setTimeReversal(int op, int val) { 255 spaceGroup.operations[op].setTimeReversal(val); 256 } 257 258 @Override getSpinOp(int op)259 public float getSpinOp(int op) { 260 return spaceGroup.operations[op].getMagneticOp(); 261 } 262 263 @Override addLatticeVectors(Lst<float[]> lattvecs)264 public boolean addLatticeVectors(Lst<float[]> lattvecs) { 265 return spaceGroup.addLatticeVectors(lattvecs); 266 } 267 268 @Override getLatticeOp()269 public int getLatticeOp() { 270 return spaceGroup.latticeOp; 271 } 272 273 @Override getOperationRsVs(int iop)274 public Matrix getOperationRsVs(int iop) { 275 return (spaceGroup.finalOperations == null ? spaceGroup.operations 276 : spaceGroup.finalOperations)[iop].rsvs; 277 } 278 279 @Override getSiteMultiplicity(P3 pt)280 public int getSiteMultiplicity(P3 pt) { 281 return spaceGroup.getSiteMultiplicity(pt, unitCell); 282 } 283 284 @Override 285 /** 286 * @param rot is a full (3+d)x(3+d) array of epsilons 287 * @param trans is a (3+d)x(1) array of translations 288 * @return Jones-Faithful representation 289 */ addOp(String code, Matrix rs, Matrix vs, Matrix sigma)290 public String addOp(String code, Matrix rs, Matrix vs, Matrix sigma) { 291 spaceGroup.isSSG = true; 292 String s = SymmetryOperation.getXYZFromRsVs(rs, vs, false); 293 int i = spaceGroup.addSymmetry(s, -1, true); 294 spaceGroup.operations[i].setSigma(code, sigma); 295 return s; 296 } 297 298 @Override getMatrixFromString(String xyz, float[] rotTransMatrix, boolean allowScaling, int modDim)299 public String getMatrixFromString(String xyz, float[] rotTransMatrix, 300 boolean allowScaling, int modDim) { 301 return SymmetryOperation.getMatrixFromString(null, xyz, rotTransMatrix, 302 allowScaling); 303 } 304 305 /// symmetryInfo //// 306 307 // symmetryInfo is (inefficiently) passed to Jmol from the adapter 308 // in lieu of saving the actual unit cell read in the reader. Not perfect. 309 // The idea was to be able to create the unit cell from "scratch" independent 310 // of the reader. 311 312 @Override getSpaceGroupName()313 public String getSpaceGroupName() { 314 return (symmetryInfo != null ? symmetryInfo.sgName 315 : spaceGroup != null ? spaceGroup.getName() : unitCell != null 316 && unitCell.name.length() > 0 ? "cell=" + unitCell.name : ""); 317 } 318 319 @Override setSpaceGroupName(String name)320 public void setSpaceGroupName(String name) { 321 if (spaceGroup != null) 322 spaceGroup.setName(name); 323 } 324 325 @Override getSpaceGroupOperationCount()326 public int getSpaceGroupOperationCount() { 327 return (symmetryInfo != null ? symmetryInfo.symmetryOperations.length 328 : spaceGroup != null && spaceGroup.finalOperations != null ? spaceGroup.finalOperations.length 329 : 0); 330 } 331 332 @Override getLatticeType()333 public String getLatticeType() { 334 return (symmetryInfo != null ? symmetryInfo.latticeType 335 : spaceGroup == null ? "P" 336 : spaceGroup.latticeType); 337 } 338 339 @Override setLatticeType(String type)340 public void setLatticeType(String type) { 341 if (spaceGroup != null) 342 spaceGroup.latticeType = type; 343 } 344 345 @Override getIntTableNumber()346 public String getIntTableNumber() { 347 return (symmetryInfo != null ? symmetryInfo.intlTableNo 348 : spaceGroup == null ? null 349 : spaceGroup.intlTableNumber); 350 } 351 352 @Override getCoordinatesAreFractional()353 public boolean getCoordinatesAreFractional() { 354 return symmetryInfo == null || symmetryInfo.coordinatesAreFractional; 355 } 356 357 @Override getCellRange()358 public int[] getCellRange() { 359 return symmetryInfo == null ? null : symmetryInfo.cellRange; 360 } 361 362 @Override getSymmetryInfoStr()363 public String getSymmetryInfoStr() { 364 return (symmetryInfo == null ? "" : symmetryInfo.infoStr); 365 } 366 367 @Override getSymmetryOperations()368 public M4[] getSymmetryOperations() { 369 if (symmetryInfo != null) 370 return symmetryInfo.symmetryOperations; 371 if (spaceGroup == null) 372 spaceGroup = SpaceGroup.getNull(true, false, true); 373 return spaceGroup.finalOperations; 374 } 375 376 @Override isSimple()377 public boolean isSimple() { 378 return (symmetryInfo == null || symmetryInfo.symmetryOperations == null); 379 } 380 381 /** 382 * Set space group and unit cell from the auxiliary info generated by the 383 * model adapter. 384 * 385 */ 386 @SuppressWarnings("unchecked") 387 @Override setSymmetryInfo(int modelIndex, Map<String, Object> modelAuxiliaryInfo, float[] unitCellParams)388 public SymmetryInterface setSymmetryInfo(int modelIndex, 389 Map<String, Object> modelAuxiliaryInfo, 390 float[] unitCellParams) { 391 symmetryInfo = new SymmetryInfo(); 392 float[] params = symmetryInfo.setSymmetryInfo(modelAuxiliaryInfo, 393 unitCellParams); 394 if (params != null) { 395 setUnitCell(params, modelAuxiliaryInfo.containsKey("jmolData")); 396 unitCell.moreInfo = (Lst<String>) modelAuxiliaryInfo 397 .get("moreUnitCellInfo"); 398 modelAuxiliaryInfo.put("infoUnitCell", getUnitCellAsArray(false)); 399 setOffsetPt((T3) modelAuxiliaryInfo.get("unitCellOffset")); 400 M3 matUnitCellOrientation = (M3) modelAuxiliaryInfo 401 .get("matUnitCellOrientation"); 402 if (matUnitCellOrientation != null) 403 initializeOrientation(matUnitCellOrientation); 404 if (Logger.debugging) 405 Logger.debug("symmetryInfos[" + modelIndex + "]:\n" 406 + unitCell.dumpInfo(true)); 407 } 408 return this; 409 } 410 411 // UnitCell methods 412 413 @Override haveUnitCell()414 public boolean haveUnitCell() { 415 return (unitCell != null); 416 } 417 418 @Override checkUnitCell(SymmetryInterface uc, P3 cell, P3 ptTemp, boolean isAbsolute)419 public boolean checkUnitCell(SymmetryInterface uc, P3 cell, P3 ptTemp, 420 boolean isAbsolute) { 421 uc.toFractional(ptTemp, isAbsolute); 422 // {1 1 1} here is the original cell 423 return (ptTemp.x >= cell.x - 1f - SimpleUnitCell.SLOP && ptTemp.x <= cell.x + SimpleUnitCell.SLOP 424 && ptTemp.y >= cell.y - 1f - SimpleUnitCell.SLOP && ptTemp.y <= cell.y + SimpleUnitCell.SLOP 425 && ptTemp.z >= cell.z - 1f - SimpleUnitCell.SLOP && ptTemp.z <= cell.z + SimpleUnitCell.SLOP); 426 } 427 428 @Override setUnitCell(float[] unitCellParams, boolean setRelative)429 public void setUnitCell(float[] unitCellParams, boolean setRelative) { 430 unitCell = UnitCell.fromParams(unitCellParams, setRelative); 431 } 432 433 @Override unitCellEquals(SymmetryInterface uc2)434 public boolean unitCellEquals(SymmetryInterface uc2) { 435 return ((Symmetry) (uc2)).unitCell.isSameAs(unitCell); 436 } 437 438 @Override getUnitCellState()439 public String getUnitCellState() { 440 return (unitCell == null ? "" : unitCell.getState()); 441 } 442 443 @Override getMoreInfo()444 public Lst<String> getMoreInfo() { 445 return unitCell.moreInfo; 446 } 447 getUnitsymmetryInfo()448 public String getUnitsymmetryInfo() { 449 // not used in Jmol? 450 return unitCell.dumpInfo(false); 451 } 452 453 @Override initializeOrientation(M3 mat)454 public void initializeOrientation(M3 mat) { 455 unitCell.initOrientation(mat); 456 } 457 458 @Override unitize(T3 ptFrac)459 public void unitize(T3 ptFrac) { 460 unitCell.unitize(ptFrac); 461 } 462 463 @Override toUnitCell(T3 pt, T3 offset)464 public void toUnitCell(T3 pt, T3 offset) { 465 unitCell.toUnitCell(pt, offset); 466 } 467 468 @Override toSupercell(P3 fpt)469 public P3 toSupercell(P3 fpt) { 470 return unitCell.toSupercell(fpt); 471 } 472 473 @Override toFractional(T3 pt, boolean ignoreOffset)474 public void toFractional(T3 pt, boolean ignoreOffset) { 475 if (!isBio) 476 unitCell.toFractional(pt, ignoreOffset); 477 } 478 479 @Override toFractionalM(M4 m)480 public void toFractionalM(M4 m) { 481 if (!isBio) 482 unitCell.toFractionalM(m); 483 } 484 485 @Override toCartesian(T3 fpt, boolean ignoreOffset)486 public void toCartesian(T3 fpt, boolean ignoreOffset) { 487 if (!isBio) 488 unitCell.toCartesian(fpt, ignoreOffset); 489 } 490 491 @Override getUnitCellParams()492 public float[] getUnitCellParams() { 493 return unitCell.getUnitCellParams(); 494 } 495 496 @Override getUnitCellAsArray(boolean vectorsOnly)497 public float[] getUnitCellAsArray(boolean vectorsOnly) { 498 return unitCell.getUnitCellAsArray(vectorsOnly); 499 } 500 501 @Override getTensor(Viewer vwr, float[] parBorU)502 public Tensor getTensor(Viewer vwr, float[] parBorU) { 503 if (parBorU == null) 504 return null; 505 if (unitCell == null) 506 unitCell = UnitCell.fromParams(new float[] { 1, 1, 1, 90, 90, 90 }, true); 507 return unitCell.getTensor(vwr, parBorU); 508 } 509 510 @Override getUnitCellVerticesNoOffset()511 public P3[] getUnitCellVerticesNoOffset() { 512 return unitCell.getVertices(); 513 } 514 515 @Override getCartesianOffset()516 public P3 getCartesianOffset() { 517 return unitCell.getCartesianOffset(); 518 } 519 520 @Override getFractionalOffset()521 public P3 getFractionalOffset() { 522 return unitCell.getFractionalOffset(); 523 } 524 525 @Override setOffsetPt(T3 pt)526 public void setOffsetPt(T3 pt) { 527 unitCell.setOffset(pt); 528 } 529 530 @Override setOffset(int nnn)531 public void setOffset(int nnn) { 532 P3 pt = new P3(); 533 SimpleUnitCell.ijkToPoint3f(nnn, pt, 0, 0); 534 unitCell.setOffset(pt); 535 } 536 537 @Override getUnitCellMultiplier()538 public T3 getUnitCellMultiplier() { 539 return unitCell.getUnitCellMultiplier(); 540 } 541 542 @Override getCanonicalCopy(float scale, boolean withOffset)543 public P3[] getCanonicalCopy(float scale, boolean withOffset) { 544 return unitCell.getCanonicalCopy(scale, withOffset); 545 } 546 547 @Override getUnitCellInfoType(int infoType)548 public float getUnitCellInfoType(int infoType) { 549 return unitCell.getInfo(infoType); 550 } 551 552 @Override getUnitCellInfo()553 public String getUnitCellInfo() { 554 return unitCell.dumpInfo(false); 555 } 556 557 @Override isSlab()558 public boolean isSlab() { 559 return unitCell.isSlab(); 560 } 561 562 @Override isPolymer()563 public boolean isPolymer() { 564 return unitCell.isPolymer(); 565 } 566 567 @Override checkDistance(P3 f1, P3 f2, float distance, float dx, int iRange, int jRange, int kRange, P3 ptOffset)568 public boolean checkDistance(P3 f1, P3 f2, float distance, float dx, 569 int iRange, int jRange, int kRange, P3 ptOffset) { 570 return unitCell.checkDistance(f1, f2, distance, dx, iRange, jRange, kRange, 571 ptOffset); 572 } 573 574 @Override getUnitCellVectors()575 public P3[] getUnitCellVectors() { 576 return unitCell.getUnitCellVectors(); 577 } 578 579 /** 580 * @param oabc [ptorigin, va, vb, vc] 581 * @param setRelative a flag only set true for IsosurfaceMesh 582 * @param name 583 * @return this SymmetryInterface 584 */ 585 @Override getUnitCell(T3[] oabc, boolean setRelative, String name)586 public SymmetryInterface getUnitCell(T3[] oabc, boolean setRelative, 587 String name) { 588 if (oabc == null) 589 return null; 590 unitCell = UnitCell.fromOABC(oabc, setRelative); 591 if (name != null) 592 unitCell.name = name; 593 return this; 594 } 595 596 @Override isSupercell()597 public boolean isSupercell() { 598 return unitCell.isSupercell(); 599 } 600 601 @Override notInCentroid(ModelSet modelSet, BS bsAtoms, int[] minmax)602 public BS notInCentroid(ModelSet modelSet, BS bsAtoms, int[] minmax) { 603 try { 604 BS bsDelete = new BS(); 605 int iAtom0 = bsAtoms.nextSetBit(0); 606 JmolMolecule[] molecules = modelSet.getMolecules(); 607 int moleculeCount = molecules.length; 608 Atom[] atoms = modelSet.at; 609 boolean isOneMolecule = (molecules[moleculeCount - 1].firstAtomIndex == modelSet.am[atoms[iAtom0].mi].firstAtomIndex); 610 P3 center = new P3(); 611 boolean centroidPacked = (minmax[6] == 1); 612 nextMol: for (int i = moleculeCount; --i >= 0 613 && bsAtoms.get(molecules[i].firstAtomIndex);) { 614 BS bs = molecules[i].atomList; 615 center.set(0, 0, 0); 616 int n = 0; 617 for (int j = bs.nextSetBit(0); j >= 0; j = bs.nextSetBit(j + 1)) { 618 if (isOneMolecule || centroidPacked) { 619 center.setT(atoms[j]); 620 if (isNotCentroid(center, 1, minmax, centroidPacked)) { 621 if (isOneMolecule) 622 bsDelete.set(j); 623 } else if (!isOneMolecule) { 624 continue nextMol; 625 } 626 } else { 627 center.add(atoms[j]); 628 n++; 629 } 630 } 631 if (centroidPacked || n > 0 && isNotCentroid(center, n, minmax, false)) 632 bsDelete.or(bs); 633 } 634 return bsDelete; 635 } catch (Exception e) { 636 return null; 637 } 638 } 639 isNotCentroid(P3 center, int n, int[] minmax, boolean centroidPacked)640 private boolean isNotCentroid(P3 center, int n, int[] minmax, 641 boolean centroidPacked) { 642 center.scale(1f / n); 643 toFractional(center, false); 644 // we have to disallow just a tiny slice of atoms due to rounding errors 645 // so -0.000001 is OK, but 0.999991 is not. 646 if (centroidPacked) 647 return (center.x + 0.000005f <= minmax[0] 648 || center.x - 0.000005f > minmax[3] 649 || center.y + 0.000005f <= minmax[1] 650 || center.y - 0.000005f > minmax[4] 651 || center.z + 0.000005f <= minmax[2] || center.z - 0.000005f > minmax[5]); 652 653 return (center.x + 0.000005f <= minmax[0] 654 || center.x + 0.00005f > minmax[3] || center.y + 0.000005f <= minmax[1] 655 || center.y + 0.00005f > minmax[4] || center.z + 0.000005f <= minmax[2] || center.z + 0.00005f > minmax[5]); 656 } 657 658 // info 659 660 private SymmetryDesc desc; 661 getDesc(ModelSet modelSet)662 private SymmetryDesc getDesc(ModelSet modelSet) { 663 return (desc == null ? (desc = ((SymmetryDesc) Interface.getInterface( 664 "org.jmol.symmetry.SymmetryDesc", modelSet.vwr, "eval"))) : desc).set(modelSet); 665 } 666 667 @Override getSymmetryInfoAtom(ModelSet modelSet, int iatom, String xyz, int op, P3 translation, P3 pt, P3 pt2, String id, int type, float scaleFactor, int nth, int options)668 public Object getSymmetryInfoAtom(ModelSet modelSet, int iatom, String xyz, 669 int op, P3 translation, P3 pt, P3 pt2, String id, int type, float scaleFactor, int nth, int options) { 670 return getDesc(modelSet).getSymopInfo(iatom, xyz, op, translation, pt, 671 pt2, id, type, scaleFactor, nth, options); 672 } 673 674 @Override getSpaceGroupInfo(ModelSet modelSet, String sgName, int modelIndex, boolean isFull, float[] cellParams)675 public Map<String, Object> getSpaceGroupInfo(ModelSet modelSet, String sgName, int modelIndex, boolean isFull, float[] cellParams) { 676 boolean isForModel = (sgName == null); 677 if (sgName == null) { 678 Map<String, Object> info = modelSet.getModelAuxiliaryInfo(modelSet.vwr.am.cmi); 679 if (info != null) 680 sgName = (String) info.get("spaceGroup"); 681 } 682 SymmetryInterface cellInfo = null; 683 if (cellParams != null) { 684 cellInfo = new Symmetry(); 685 cellInfo.setUnitCell(cellParams, false); 686 } 687 return getDesc(modelSet).getSpaceGroupInfo(this, modelIndex, sgName, 0, null, null, 688 null, 0, -1, isFull, isForModel, 0, cellInfo); 689 } 690 691 692 @Override fcoord(T3 p)693 public String fcoord(T3 p) { 694 return SymmetryOperation.fcoord(p); 695 } 696 697 @Override getV0abc(Object def)698 public T3[] getV0abc(Object def) { 699 return (unitCell == null ? null : unitCell.getV0abc(def)); 700 } 701 702 @Override getQuaternionRotation(String abc)703 public Quat getQuaternionRotation(String abc) { 704 return (unitCell == null ? null : unitCell.getQuaternionRotation(abc)); 705 } 706 707 @Override getFractionalOrigin()708 public T3 getFractionalOrigin() { 709 return unitCell.getFractionalOrigin(); 710 } 711 712 @Override getState(SB commands)713 public boolean getState(SB commands) { 714 T3 pt = getFractionalOffset(); 715 boolean loadUC = false; 716 if (pt != null && (pt.x != 0 || pt.y != 0 || pt.z != 0)) { 717 commands.append("; set unitcell ").append(Escape.eP(pt)); 718 loadUC = true; 719 } 720 pt = getUnitCellMultiplier(); 721 if (pt != null) { 722 commands.append("; set unitcell ").append(SimpleUnitCell.escapeMultiplier(pt)); 723 loadUC = true; 724 } 725 return loadUC; 726 } 727 728 @Override getIterator(Viewer vwr, Atom atom, Atom[] atoms, BS bsAtoms, float radius)729 public AtomIndexIterator getIterator(Viewer vwr, Atom atom, Atom[] atoms, 730 BS bsAtoms, float radius) { 731 return ((UnitCellIterator) Interface.getInterface("org.jmol.symmetry.UnitCellIterator", vwr, "script")) 732 .set(this, atom, atoms, bsAtoms, radius); 733 } 734 735 @Override toFromPrimitive(boolean toPrimitive, char type, T3[] oabc, M3 primitiveToCrystal)736 public boolean toFromPrimitive(boolean toPrimitive, char type, T3[] oabc, M3 primitiveToCrystal) { 737 if (unitCell == null) 738 unitCell = UnitCell.fromOABC(oabc, false); 739 return unitCell.toFromPrimitive(toPrimitive, type, oabc, primitiveToCrystal); 740 } 741 742 @Override generateCrystalClass(P3 pt0)743 public Lst<P3> generateCrystalClass(P3 pt0) { 744 M4[] ops = getSymmetryOperations(); 745 Lst<P3> lst = new Lst<P3>(); 746 boolean isRandom = (pt0 == null); 747 float rand1=0,rand2=0,rand3=0; 748 if (isRandom) { 749 rand1 = (float) Math.E; 750 rand2 = (float) Math.PI; 751 rand3 = (float) Math.log10(2000); 752 pt0 = P3.new3(rand1 + 1, rand2 + 2, rand3 + 3); 753 } else { 754 pt0 = P3.newP(pt0); 755 } 756 if (ops == null || unitCell == null) { 757 lst.addLast(pt0); 758 } else { 759 unitCell.toFractional(pt0, true); // ignoreOffset 760 P3 pt1 = null; 761 P3 pt2 = null; 762 P3 pt3 = null; 763 if (isRandom) { 764 pt1 = P3.new3(rand2 + 4, rand3 + 5, rand1 + 6); 765 unitCell.toFractional(pt1, true); // ignoreOffset 766 pt2 = P3.new3(rand3 + 7, rand1 + 8, rand2 + 9); 767 unitCell.toFractional(pt2, true); // ignoreOffset 768 } 769 Bspt bspt = new Bspt(3, 0); 770 CubeIterator iter = bspt.allocateCubeIterator(); 771 P3 pt = new P3(); 772 out: for (int i = ops.length; --i >= 0;) { 773 ops[i].rotate2(pt0, pt); 774 iter.initialize(pt, 0.001f, false); 775 if (iter.hasMoreElements()) 776 continue out; 777 P3 ptNew = P3.newP(pt); 778 lst.addLast(ptNew); 779 bspt.addTuple(ptNew); 780 if (isRandom) { 781 if (pt2 != null) { 782 pt3 = new P3(); 783 ops[i].rotate2(pt2, pt3); 784 lst.addLast(pt3); 785 } 786 if (pt1 != null) { 787 // pt2 is necessary to distinguish between Cs, Ci, and C1 788 pt3 = new P3(); 789 ops[i].rotate2(pt1, pt3); 790 lst.addLast(pt3); 791 } 792 } 793 } 794 for (int j = lst.size(); --j >= 0;) 795 unitCell.toCartesian(lst.get(j), true); // ignoreOffset 796 } 797 return lst; 798 } 799 800 @Override calculateCIPChiralityForAtoms(Viewer vwr, BS bsAtoms)801 public void calculateCIPChiralityForAtoms(Viewer vwr, BS bsAtoms) { 802 vwr.setCursor(GenericPlatform.CURSOR_WAIT); 803 CIPChirality cip = getCIPChirality(vwr); 804 String dataClass = (vwr.getBoolean(T.testflag1) ? "CIPData" : "CIPDataTracker"); 805 CIPData data = ((CIPData) Interface.getInterface("org.jmol.symmetry." + dataClass, vwr, "script")).set(vwr, bsAtoms); 806 data.setRule6Full(vwr.getBoolean(T.ciprule6full)); 807 cip.getChiralityForAtoms(data); 808 vwr.setCursor(GenericPlatform.CURSOR_DEFAULT); 809 } 810 811 @Override calculateCIPChiralityForSmiles(Viewer vwr, String smiles)812 public String[] calculateCIPChiralityForSmiles(Viewer vwr, String smiles) throws Exception { 813 vwr.setCursor(GenericPlatform.CURSOR_WAIT); 814 CIPChirality cip = getCIPChirality(vwr); 815 CIPDataSmiles data = ((CIPDataSmiles) Interface.getInterface("org.jmol.symmetry.CIPDataSmiles", vwr, "script")).setAtomsForSmiles(vwr, smiles); 816 cip.getChiralityForAtoms(data); 817 vwr.setCursor(GenericPlatform.CURSOR_DEFAULT); 818 return data.getSmilesChiralityArray(); 819 } 820 821 CIPChirality cip; 822 getCIPChirality(Viewer vwr)823 private CIPChirality getCIPChirality(Viewer vwr) { 824 return (cip == null ? (cip = ((CIPChirality) Interface.getInterface("org.jmol.symmetry.CIPChirality", vwr, "script"))) : cip); 825 } 826 827 828 /** 829 * return a conventional lattice from a primitive 830 * 831 * @param latticeType 832 * "A" "B" "C" "R" etc. 833 * @return [origin va vb vc] 834 */ 835 @Override getConventionalUnitCell(String latticeType, M3 primitiveToCrystal)836 public T3[] getConventionalUnitCell(String latticeType, 837 M3 primitiveToCrystal) { 838 return (unitCell == null || latticeType == null ? null 839 : unitCell.getConventionalUnitCell(latticeType, primitiveToCrystal)); 840 } 841 842 @Override getUnitCellInfoMap()843 public Map<String, Object> getUnitCellInfoMap() { 844 return (unitCell == null ? null : unitCell.getInfo()); 845 } 846 847 @Override setUnitCell(Symmetry uc)848 public void setUnitCell(Symmetry uc) { 849 unitCell = UnitCell.cloneUnitCell(uc.unitCell); 850 } 851 852 } 853