1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2021-09-07 18:56:03 -0500 (Tue, 07 Sep 2021) $ 4 * $Revision: 22229 $ 5 6 * 7 * Copyright (C) 2003-2005 The Jmol Development Team 8 * 9 * Contact: jmol-developers@lists.sf.net 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2.1 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 24 */ 25 26 package org.jmol.modelset; 27 28 import javajs.util.CU; 29 import javajs.util.Lst; 30 import javajs.util.P3; 31 import javajs.util.PT; 32 import javajs.util.SB; 33 import javajs.util.T3; 34 import javajs.util.V3; 35 36 import org.jmol.api.JmolDataManager; 37 import org.jmol.api.JmolModulationSet; 38 import org.jmol.api.SymmetryInterface; 39 import org.jmol.atomdata.RadiusData; 40 import org.jmol.atomdata.RadiusData.EnumType; 41 import org.jmol.c.PAL; 42 import org.jmol.c.VDW; 43 import javajs.util.BS; 44 import org.jmol.modelsetbio.BioModel; 45 import org.jmol.script.T; 46 import org.jmol.util.C; 47 import org.jmol.util.Edge; 48 import org.jmol.util.Elements; 49 import org.jmol.util.Node; 50 import org.jmol.util.Point3fi; 51 import org.jmol.util.Tensor; 52 import org.jmol.util.Vibration; 53 import org.jmol.viewer.JC; 54 import org.jmol.viewer.Viewer; 55 56 57 58 59 public class Atom extends Point3fi implements Node { 60 61 // ATOM_IN_FRAME simply associates an atom with the current model 62 // but doesn't necessarily mean it is visible 63 // ATOM_VIS_SET and ATOM_VISIBLE are checked once only for each atom per rendering 64 65 public final static int ATOM_INFRAME = 1; 66 public final static int ATOM_VISSET = 2; // have carried out checkVisible() 67 public final static int ATOM_VISIBLE = 4; // set from checkVisible() 68 public final static int ATOM_NOTHIDDEN = 8; 69 public final static int ATOM_NOFLAGS = ~63; // all of the above, plus balls and sticks 70 public final static int ATOM_INFRAME_NOTHIDDEN = ATOM_INFRAME | ATOM_NOTHIDDEN; 71 public final static int ATOM_SHAPE_VIS_MASK = ~ATOM_INFRAME_NOTHIDDEN; 72 73 74 public static final int RADIUS_MAX = 16; 75 public static final float RADIUS_GLOBAL = 16.1f; 76 public static short MAD_GLOBAL = 32200; 77 78 public char altloc = '\0'; 79 public byte atomID; 80 public int atomSite; 81 public Group group; 82 private float userDefinedVanDerWaalRadius; 83 byte valence; 84 private short atomicAndIsotopeNumber; 85 public BS atomSymmetry; 86 87 private int formalChargeAndFlags; // cccc CIP_ _CIP --hv 88 89 private final static int CHARGE_OFFSET = 24; 90 91 private final static int FLAG_MASK = 0xF; 92 private final static int VIBRATION_VECTOR_FLAG = 1; 93 private final static int IS_HETERO_FLAG = 2; 94 95 private final static int CIP_CHIRALITY_OFFSET = 4; 96 private final static int CIP_CHIRALITY_MASK = 0x1F0; 97 private final static int CIP_CHIRALITY_RULE_OFFSET = 9; 98 private final static int CIP_CHIRALITY_RULE_MASK = 0xE00; 99 private final static int CIP_MASK = CIP_CHIRALITY_MASK | CIP_CHIRALITY_RULE_MASK; 100 101 public short madAtom; 102 103 public short colixAtom; 104 public byte paletteID = PAL.CPK.id; 105 106 /** 107 * 108 * MAY BE NULL 109 * 110 */ 111 public Bond[] bonds; 112 113 private int nBondsDisplayed = 0; 114 public int nBackbonesDisplayed = 0; 115 116 public int clickabilityFlags; 117 public int shapeVisibilityFlags; 118 119 /** 120 * @j2sIgnoreSuperConstructor 121 * @j2sOverride 122 * 123 * @param modelIndex 124 * @param atomIndex 125 * @param xyz 126 * @param radius 127 * @param atomSymmetry 128 * @param atomSite 129 * @param atomicAndIsotopeNumber 130 * @param formalCharge 131 * @param isHetero 132 * @return this 133 */ 134 setAtom(int modelIndex, int atomIndex, P3 xyz, float radius, BS atomSymmetry, int atomSite, short atomicAndIsotopeNumber, int formalCharge, boolean isHetero)135 public Atom setAtom(int modelIndex, int atomIndex, 136 P3 xyz, float radius, 137 BS atomSymmetry, int atomSite, 138 short atomicAndIsotopeNumber, int formalCharge, 139 boolean isHetero) { 140 this.mi = (short)modelIndex; 141 this.atomSymmetry = atomSymmetry; 142 this.atomSite = atomSite; 143 this.i = atomIndex; 144 this.atomicAndIsotopeNumber = atomicAndIsotopeNumber; 145 if (isHetero) 146 formalChargeAndFlags = IS_HETERO_FLAG; 147 if (formalCharge != 0 && formalCharge != Integer.MIN_VALUE) 148 setFormalCharge(formalCharge); 149 userDefinedVanDerWaalRadius = radius; 150 setT(xyz); 151 return this; 152 } 153 setShapeVisibility(int flag, boolean isVisible)154 public final void setShapeVisibility(int flag, boolean isVisible) { 155 if(isVisible) 156 shapeVisibilityFlags |= flag; 157 else 158 shapeVisibilityFlags &=~flag; 159 } 160 isCovalentlyBonded(Atom atomOther)161 public boolean isCovalentlyBonded(Atom atomOther) { 162 if (bonds != null) 163 for (int i = bonds.length; --i >= 0;) 164 if (bonds[i].isCovalent() 165 && bonds[i].getOtherAtom(this) == atomOther) 166 return true; 167 return false; 168 } 169 isBonded(Atom atomOther)170 public boolean isBonded(Atom atomOther) { 171 if (bonds != null) 172 for (int i = bonds.length; --i >= 0;) 173 if (bonds[i].getOtherAtom(this) == atomOther) 174 return true; 175 return false; 176 } 177 getBond(Atom atomOther)178 public Bond getBond(Atom atomOther) { 179 if (bonds != null) 180 for (int i = bonds.length; --i >= 0;) 181 if (bonds[i].getOtherAtom(atomOther) != null) 182 return bonds[i]; 183 return null; 184 } 185 186 addDisplayedBond(int stickVisibilityFlag, boolean isVisible)187 void addDisplayedBond(int stickVisibilityFlag, boolean isVisible) { 188 nBondsDisplayed += (isVisible ? 1 : -1); 189 setShapeVisibility(stickVisibilityFlag, (nBondsDisplayed > 0)); 190 } 191 deleteBond(Bond bond)192 void deleteBond(Bond bond) { 193 // this one is used -- from Bond.deleteAtomReferences 194 if (bonds != null) 195 for (int i = bonds.length; --i >= 0;) 196 if (bonds[i] == bond) { 197 deleteBondAt(i); 198 return; 199 } 200 } 201 deleteBondAt(int i)202 private void deleteBondAt(int i) { 203 setCIPChirality(0); 204 int newLength = bonds.length - 1; 205 if (newLength == 0) { 206 bonds = null; 207 return; 208 } 209 Bond[] bondsNew = new Bond[newLength]; 210 int j = 0; 211 for ( ; j < i; ++j) 212 bondsNew[j] = bonds[j]; 213 for ( ; j < newLength; ++j) 214 bondsNew[j] = bonds[j + 1]; 215 bonds = bondsNew; 216 } 217 218 @Override getBondedAtomIndex(int bondIndex)219 public int getBondedAtomIndex(int bondIndex) { 220 return bonds[bondIndex].getOtherAtom(this).i; 221 } 222 223 /* 224 * What is a MAR? 225 * - just a term that Miguel made up 226 * - an abbreviation for Milli Angstrom Radius 227 * that is: 228 * - a *radius* of either a bond or an atom 229 * - in *millis*, or thousandths of an *angstrom* 230 * - stored as a short 231 * 232 * However! In the case of an atom radius, if the parameter 233 * gets passed in as a negative number, then that number 234 * represents a percentage of the vdw radius of that atom. 235 * This is converted to a normal MAR as soon as possible 236 * 237 * (I know almost everyone hates bytes & shorts, but I like them ... 238 * gives me some tiny level of type-checking ... 239 * a rudimentary form of enumerations/user-defined primitive types) 240 */ 241 setMadAtom(Viewer vwr, RadiusData rd)242 public void setMadAtom(Viewer vwr, RadiusData rd) { 243 madAtom = calculateMad(vwr, rd); 244 } 245 calculateMad(Viewer vwr, RadiusData rd)246 public short calculateMad(Viewer vwr, RadiusData rd) { 247 if (rd == null) 248 return 0; 249 float f = rd.value; 250 if (f == 0) 251 return 0; 252 switch (rd.factorType) { 253 case SCREEN: 254 return (short) f; 255 case FACTOR: 256 case OFFSET: 257 float r = 0; 258 switch (rd.vdwType) { 259 case TEMP: 260 float tmax = vwr.ms.getBfactor100Hi(); 261 r = (tmax > 0 ? getBfactor100() / tmax : 0); 262 break; 263 case HYDRO: 264 r = Math.abs(getHydrophobicity()); 265 break; 266 case BONDING: 267 r = getBondingRadius(); 268 break; 269 case ADPMIN: 270 case ADPMAX: 271 r = getADPMinMax(rd.vdwType == VDW.ADPMAX); 272 break; 273 default: 274 r = getVanderwaalsRadiusFloat(vwr, rd.vdwType); 275 } 276 if (rd.factorType == EnumType.FACTOR) 277 f *= r; 278 else 279 f += r; 280 break; 281 case ABSOLUTE: 282 if (f == RADIUS_GLOBAL) 283 return MAD_GLOBAL; 284 break; 285 } 286 short mad = (short) (f < 0 ? f: f * 2000); 287 if (mad < 0 && f > 0) 288 mad = 0; 289 return mad; 290 } 291 getADPMinMax(boolean isMax)292 public float getADPMinMax(boolean isMax) { 293 Object[] tensors = getTensors(); 294 if (tensors == null) 295 return 0; 296 Tensor t = (Tensor) tensors[0]; 297 if (t == null || t.iType != Tensor.TYPE_ADP) 298 return 0; 299 if (group.chain.model.ms.isModulated(i) && t.isUnmodulated) 300 t = (Tensor) tensors[1]; 301 return t.getFactoredValue(isMax ? 2 : 1); 302 } 303 getTensors()304 public Object[] getTensors() { 305 return group.chain.model.ms.getAtomTensorList(i); 306 } 307 getRasMolRadius()308 public int getRasMolRadius() { 309 return Math.abs(madAtom / 8); // 1000r = 1000d / 2; rr = (1000r / 4); 310 } 311 312 @Override getEdges()313 public Edge[] getEdges() { 314 return (bonds == null ? new Edge[0] : bonds); 315 } 316 317 @Override getBondCount()318 public int getBondCount() { 319 return (bonds == null ? 0 : bonds.length); 320 } 321 setTranslucent(boolean isTranslucent, float translucentLevel)322 public void setTranslucent(boolean isTranslucent, float translucentLevel) { 323 colixAtom = C.getColixTranslucent3(colixAtom, isTranslucent, translucentLevel); 324 } 325 326 @Override getElementNumber()327 public int getElementNumber() { 328 return Elements.getElementNumber(atomicAndIsotopeNumber); 329 } 330 331 @Override getIsotopeNumber()332 public int getIsotopeNumber() { 333 return Elements.getIsotopeNumber(atomicAndIsotopeNumber); 334 } 335 336 @Override getAtomicAndIsotopeNumber()337 public int getAtomicAndIsotopeNumber() { 338 return atomicAndIsotopeNumber; 339 } 340 setAtomicAndIsotopeNumber(int n)341 public void setAtomicAndIsotopeNumber(int n) { 342 if (n < 0 || (n & 127) >= Elements.elementNumberMax || n > Short.MAX_VALUE) 343 n = 0; 344 atomicAndIsotopeNumber = (short) n; 345 } 346 getElementSymbolIso(boolean withIsotope)347 public String getElementSymbolIso(boolean withIsotope) { 348 return Elements.elementSymbolFromNumber(withIsotope ? atomicAndIsotopeNumber : atomicAndIsotopeNumber & 127); 349 } 350 getElementSymbol()351 public String getElementSymbol() { 352 return getElementSymbolIso(true); 353 } 354 isHetero()355 public boolean isHetero() { 356 return (formalChargeAndFlags & IS_HETERO_FLAG) != 0; 357 } 358 hasVibration()359 public boolean hasVibration() { 360 return (formalChargeAndFlags & VIBRATION_VECTOR_FLAG) != 0; 361 } 362 363 /** 364 * 365 * @param charge from -3 to 7 366 */ setFormalCharge(int charge)367 public void setFormalCharge(int charge) { 368 formalChargeAndFlags = (formalChargeAndFlags & FLAG_MASK) 369 | ((charge == Integer.MIN_VALUE ? 0 : charge > 7 ? 7 : charge < -3 ? -3 : charge) << CHARGE_OFFSET); 370 } 371 setVibrationVector()372 void setVibrationVector() { 373 formalChargeAndFlags |= VIBRATION_VECTOR_FLAG; 374 } 375 376 @Override getFormalCharge()377 public int getFormalCharge() { 378 return formalChargeAndFlags >> CHARGE_OFFSET; 379 } 380 381 // a percentage value in the range 0-100 getOccupancy100()382 public int getOccupancy100() { 383 float[] occupancies = group.chain.model.ms.occupancies; 384 return (occupancies == null ? 100 : Math.round(occupancies[i])); 385 } 386 387 // a percentage value in the range 0-100 isOccupied()388 public boolean isOccupied() { 389 float[] occupancies = group.chain.model.ms.occupancies; 390 return (occupancies == null || occupancies[i] >= 50); 391 } 392 393 // This is called bfactor100 because it is stored as an integer 394 // 100 times the bfactor(temperature) value getBfactor100()395 public int getBfactor100() { 396 short[] bfactor100s = group.chain.model.ms.bfactor100s; 397 return (bfactor100s == null ? 0 : bfactor100s[i]); 398 } 399 getHydrophobicity()400 public float getHydrophobicity() { 401 float[] values = group.chain.model.ms.hydrophobicities; 402 return (values == null ? Elements.getHydrophobicity(group.groupID) : values[i]); 403 } 404 setRadius(float radius)405 public boolean setRadius(float radius) { 406 return !Float.isNaN(userDefinedVanDerWaalRadius = (radius > 0 ? radius : Float.NaN)); 407 } 408 delete(BS bsBonds)409 public void delete(BS bsBonds) { 410 valence = -1; 411 if (bonds != null) 412 for (int i = bonds.length; --i >= 0; ) { 413 Bond bond = bonds[i]; 414 bond.getOtherAtom(this).deleteBond(bond); 415 bsBonds.set(bond.index); 416 } 417 bonds = null; 418 } 419 420 @Override isDeleted()421 public boolean isDeleted() { 422 return (valence < 0); 423 } 424 setValence(int nBonds)425 public void setValence(int nBonds) { 426 if (!isDeleted()) // no resurrection 427 valence = (byte) (nBonds < 0 ? 0 : nBonds <= 0x7F ? nBonds : 0x7F); 428 } 429 430 /** 431 * return the total bond order for this atom 432 */ 433 @Override getValence()434 public int getValence() { 435 if (isDeleted()) 436 return -1; 437 int n = valence; 438 if (n == 0 && bonds != null) 439 for (int i = bonds.length; --i >= 0;) 440 n += bonds[i].getValence(); 441 return n; 442 } 443 444 @Override getCovalentBondCount()445 public int getCovalentBondCount() { 446 if (bonds == null) 447 return 0; 448 int n = 0; 449 Bond b; 450 for (int i = bonds.length; --i >= 0; ) 451 if (((b = bonds[i]).order & Edge.BOND_COVALENT_MASK) != 0 452 && !b.getOtherAtom(this).isDeleted()) 453 ++n; 454 return n; 455 } 456 457 @Override getCovalentHydrogenCount()458 public int getCovalentHydrogenCount() { 459 if (bonds == null) 460 return 0; 461 int n = 0; 462 for (int i = bonds.length; --i >= 0; ) { 463 if ((bonds[i].order & Edge.BOND_COVALENT_MASK) == 0) 464 continue; 465 Atom a = bonds[i].getOtherAtom(this); 466 if (a.valence >= 0 && a.getElementNumber() == 1) 467 ++n; 468 } 469 return n; 470 } 471 472 @Override getImplicitHydrogenCount()473 public int getImplicitHydrogenCount() { 474 return group.chain.model.ms.getMissingHydrogenCount(this, false); 475 } 476 477 @Override getTotalHydrogenCount()478 public int getTotalHydrogenCount() { 479 return getCovalentHydrogenCount() + getImplicitHydrogenCount(); 480 } 481 482 @Override getTotalValence()483 public int getTotalValence() { 484 int v = getValence(); 485 if (v < 0) 486 return v; 487 int h = getImplicitHydrogenCount(); 488 int sp2 = group.chain.model.ms.aaRet[4]; // 1 or 0 489 return v + h + sp2; 490 } 491 492 @Override getCovalentBondCountPlusMissingH()493 public int getCovalentBondCountPlusMissingH() { 494 return getCovalentBondCount() + getImplicitHydrogenCount(); 495 } 496 getTargetValence()497 int getTargetValence() { 498 switch (getElementNumber()) { 499 case 6: //C 500 case 14: //Si 501 case 32: // Ge 502 return 4; 503 case 5: // B 504 case 7: // N 505 case 15: // P 506 return 3; 507 case 8: //O 508 case 16: //S 509 return 2; 510 case 1: 511 case 9: // F 512 case 17: // Cl 513 case 35: // Br 514 case 53: // I 515 return 1; 516 } 517 return -1; 518 } 519 520 getDimensionValue(int dimension)521 public float getDimensionValue(int dimension) { 522 return (dimension == 0 ? x : (dimension == 1 ? y : z)); 523 } 524 getVanderwaalsRadiusFloat(Viewer vwr, VDW type)525 public float getVanderwaalsRadiusFloat(Viewer vwr, VDW type) { 526 // called by atomPropertyFloat as VDW_AUTO, 527 // AtomCollection.fillAtomData with VDW_AUTO or VDW_NOJMOL 528 // AtomCollection.findMaxRadii with VDW_AUTO 529 // AtomCollection.getAtomPropertyState with VDW_AUTO 530 // AtomCollection.getVdwRadius with passed on type 531 return (Float.isNaN(userDefinedVanDerWaalRadius) 532 ? vwr.getVanderwaalsMarType(atomicAndIsotopeNumber, getVdwType(type)) / 1000f 533 : userDefinedVanDerWaalRadius); 534 } 535 536 /** 537 * 538 * @param type 539 * @return if VDW_AUTO, will return VDW_AUTO_JMOL, VDW_AUTO_RASMOL, or VDW_AUTO_BABEL 540 * based on the model type 541 */ 542 @SuppressWarnings("incomplete-switch") getVdwType(VDW type)543 private VDW getVdwType(VDW type) { 544 switch (type) { 545 case AUTO: 546 type = group.chain.model.ms.getDefaultVdwType(mi); 547 break; 548 case NOJMOL: 549 type = group.chain.model.ms.getDefaultVdwType(mi); 550 if (type == VDW.AUTO_JMOL) 551 type = VDW.AUTO_BABEL; 552 break; 553 } 554 return type; 555 } 556 getBondingRadius()557 public float getBondingRadius() { 558 float[] rr = group.chain.model.ms.bondingRadii; 559 float r = (rr == null || i >= rr.length ? 0 : rr[i]); 560 return (r == 0 ? Elements.getBondingRadius(atomicAndIsotopeNumber, 561 getFormalCharge()) : r); 562 } 563 getVolume(Viewer vwr, VDW vType)564 float getVolume(Viewer vwr, VDW vType) { 565 float r1 = (vType == null ? userDefinedVanDerWaalRadius : Float.NaN); 566 if (Float.isNaN(r1)) 567 r1 = vwr.getVanderwaalsMarType(getElementNumber(), getVdwType(vType)) / 1000f; 568 double volume = 0; 569 if (bonds != null) 570 for (int j = 0; j < bonds.length; j++) { 571 if (!bonds[j].isCovalent()) 572 continue; 573 Atom atom2 = bonds[j].getOtherAtom(this); 574 float r2 = (vType == null ? atom2.userDefinedVanDerWaalRadius : Float.NaN); 575 if (Float.isNaN(r2)) 576 r2 = vwr.getVanderwaalsMarType(atom2.getElementNumber(), atom2 577 .getVdwType(vType)) / 1000f; 578 float d = distance(atom2); 579 if (d > r1 + r2) 580 continue; 581 if (d + r1 <= r2) 582 return 0; 583 584 // calculate hidden spherical cap height and volume 585 // A.Bondi, J. Phys. Chem. 68, 1964, 441-451. 586 587 double h = r1 - (r1 * r1 + d * d - r2 * r2) / (2.0 * d); 588 volume -= Math.PI / 3 * h * h * (3 * r1 - h); 589 } 590 return (float) (volume + 4 * Math.PI / 3 * r1 * r1 * r1); 591 } 592 getCurrentBondCount()593 int getCurrentBondCount() { 594 return bonds == null ? 0 : bonds.length; 595 } 596 getRadius()597 public float getRadius() { 598 return Math.abs(madAtom / 2000f); 599 } 600 601 @Override getIndex()602 public int getIndex() { 603 return i; 604 } 605 606 @Override getAtomSite()607 public int getAtomSite() { 608 return atomSite; 609 } 610 611 @Override getGroupBits(BS bs)612 public void getGroupBits(BS bs) { 613 group.setAtomBits(bs); 614 } 615 616 @Override getAtomName()617 public String getAtomName() { 618 return (atomID > 0 ? Group.specialAtomNames[atomID] 619 : group.chain.model.ms.atomNames == null ? "" : group.chain.model.ms.atomNames[i]); 620 } 621 622 @Override getAtomType()623 public String getAtomType() { 624 String[] atomTypes = group.chain.model.ms.atomTypes; 625 String type = (atomTypes == null ? null : atomTypes[i]); 626 return (type == null ? getAtomName() : type); 627 } 628 629 @Override getAtomNumber()630 public int getAtomNumber() { 631 int[] atomSerials = group.chain.model.ms.atomSerials; 632 // shouldn't ever be null. 633 return (atomSerials == null ? i : atomSerials[i]); 634 // : group.chain.model.modelSet.isZeroBased ? atomIndex : atomIndex); 635 } 636 getSeqID()637 public int getSeqID() { 638 int[] ids = group.chain.model.ms.atomSeqIDs; 639 return (ids == null ? 0 : ids[i]); 640 } isVisible(int flags)641 public boolean isVisible(int flags) { 642 return ((shapeVisibilityFlags & flags) == flags); 643 } 644 getPartialCharge()645 public float getPartialCharge() { 646 float[] partialCharges = group.chain.model.ms.partialCharges; 647 return partialCharges == null ? 0 : partialCharges[i]; 648 } 649 650 /** 651 * Given a symmetry operation number, the set of cells in the model, and the 652 * number of operations, this method returns either 0 or the cell number (555, 666) 653 * of the translated symmetry operation corresponding to this atom. 654 * 655 * atomSymmetry is a bitset that is created in adapter.smarter.AtomSetCollection 656 * 657 * It is arranged as follows: 658 * 659 * |--overall--|---cell1---|---cell2---|---cell3---|... 660 * 661 * |012..nOps-1|012..nOps-1|012..nOp-1s|012..nOps-1|... 662 * 663 * If a bit is set, it means that the atom was created using that operator 664 * operating on the base file set and translated for that cell. 665 * 666 * If any bit is set in any of the cell blocks, then the same 667 * bit will also be set in the overall block. This allows for 668 * rapid determination of special positions and also of 669 * atom membership in any operation set. 670 * 671 * Note that it is not necessarily true that an atom is IN the designated 672 * cell, because one can load {nnn mmm 0}, and then, for example, the {-x,-y,-z} 673 * operator sends atoms from 555 to 444. Still, those atoms would be marked as 674 * cell 555 here, because no translation was carried out. 675 * 676 * That is, the numbers 444 in symop=3444 do not refer to a cell, per se. 677 * What they refer to is the file-designated operator plus a translation of 678 * {-1 -1 -1/1}. 679 * 680 * @param symop = 0, 1, 2, 3, .... 681 * @param cellRange = {444, 445, 446, 454, 455, 456, .... } 682 * @param nOps = 2 for x,y,z;-x,-y,-z, for example 683 * @return cell number such as 565 684 */ getSymmetryTranslation(int symop, int[] cellRange, int nOps)685 public int getSymmetryTranslation(int symop, int[] cellRange, int nOps) { 686 int pt = symop; 687 for (int i = 0; i < cellRange.length; i++) 688 if (atomSymmetry.get(pt += nOps)) 689 return cellRange[i]; 690 return 0; 691 } 692 693 /** 694 * Looks for a match in the cellRange list for this atom within the specified translation set 695 * select symop=0NNN for this 696 * 697 * @param cellNNN 698 * @param cellRange 699 * @param nOps 700 * @return matching cell number, if applicable 701 */ getCellTranslation(int cellNNN, int[] cellRange, int nOps)702 public int getCellTranslation(int cellNNN, int[] cellRange, int nOps) { 703 int pt = nOps; 704 for (int i = 0; i < cellRange.length; i++) 705 for (int j = 0; j < nOps;j++, pt++) 706 if (atomSymmetry.get(pt) && cellRange[i] == cellNNN) 707 return cellRange[i]; 708 return 0; 709 } 710 getSymmetryOperatorList(boolean isAll)711 String getSymmetryOperatorList(boolean isAll) { 712 String str = ""; 713 ModelSet f = group.chain.model.ms; 714 int nOps = f.getModelSymmetryCount(mi); 715 if (nOps == 0 || atomSymmetry == null) 716 return ""; 717 int[] cellRange = f.getModelCellRange(mi); 718 int pt = nOps; 719 int n = (cellRange == null ? 1 : cellRange.length); 720 BS bs = (isAll ? null : new BS()); 721 for (int i = 0; i < n; i++) 722 for (int j = 0; j < nOps; j++) 723 if (atomSymmetry.get(pt++)) 724 if (isAll) { 725 str += "," + (j + 1) + cellRange[i]; 726 } else { 727 bs.set(j + 1); 728 } 729 if (!isAll) 730 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 731 str += "," + i; 732 return (str.length() == 0 ? "" : str.substring(1)); 733 } 734 735 /** 736 * SMILES only 737 */ 738 @Override getModelIndex()739 public int getModelIndex() { 740 return mi; 741 } 742 743 @Override getMoleculeNumber(boolean inModel)744 public int getMoleculeNumber(boolean inModel) { 745 return (group.chain.model.ms.getMoleculeIndex(i, inModel) + 1); 746 } 747 getFractionalCoord(boolean fixJavaFloat, char ch, boolean ignoreOffset, P3 pt)748 private float getFractionalCoord(boolean fixJavaFloat, char ch, boolean ignoreOffset, P3 pt) { 749 pt = getFractionalCoordPt(fixJavaFloat, ignoreOffset, pt); 750 return (ch == 'X' ? pt.x : ch == 'Y' ? pt.y : pt.z); 751 } 752 753 @Override getXYZ()754 public P3 getXYZ() { 755 return this; 756 } 757 getFractionalCoordPt(boolean fixJavaFloat, boolean ignoreOffset, P3 pt)758 public P3 getFractionalCoordPt(boolean fixJavaFloat, boolean ignoreOffset, P3 pt) { 759 // ignoreOffset TRUE uses the original unshifted matrix 760 SymmetryInterface c = getUnitCell(); 761 if (c == null) 762 return this; 763 if (pt == null) 764 pt = P3.newP(this); 765 else 766 pt.setT(this); 767 c.toFractional(pt, ignoreOffset); 768 if (fixJavaFloat) 769 PT.fixPtFloats(pt, PT.FRACTIONAL_PRECISION); 770 return pt; 771 } 772 getUnitCell()773 SymmetryInterface getUnitCell() { 774 return group.chain.model.ms.getUnitCellForAtom(this.i); 775 } 776 getFractionalUnitCoord(boolean fixJavaFloat, char ch, P3 pt)777 private float getFractionalUnitCoord(boolean fixJavaFloat, char ch, P3 pt) { 778 pt = getFractionalUnitCoordPt(fixJavaFloat, false, pt); 779 return (ch == 'X' ? pt.x : ch == 'Y' ? pt.y : pt.z); 780 } 781 782 /** 783 * @param fixJavaFloat ALWAYS set true for any new references to this method. False is for legacy only 784 * @param asCartesian 785 * @param pt 786 * @return unit cell coord 787 */ getFractionalUnitCoordPt(boolean fixJavaFloat, boolean asCartesian, P3 pt)788 P3 getFractionalUnitCoordPt(boolean fixJavaFloat, boolean asCartesian, P3 pt) { 789 SymmetryInterface c = getUnitCell(); 790 if (c == null) 791 return this; 792 if (pt == null) 793 pt = P3.newP(this); 794 else 795 pt.setT(this); 796 if (group.chain.model.isJmolDataFrame) { 797 c.toFractional(pt, false); 798 if (asCartesian) 799 c.toCartesian(pt, false); 800 } else { 801 c.toUnitCell(pt, null); 802 if (!asCartesian) 803 c.toFractional(pt, false); 804 } 805 if (fixJavaFloat) 806 PT.fixPtFloats(pt, asCartesian ? PT.CARTESIAN_PRECISION : PT.FRACTIONAL_PRECISION); 807 return pt; 808 } 809 getFractionalUnitDistance(T3 pt, T3 ptTemp1, T3 ptTemp2)810 float getFractionalUnitDistance(T3 pt, T3 ptTemp1, T3 ptTemp2) { 811 SymmetryInterface c = getUnitCell(); 812 if (c == null) 813 return distance(pt); 814 ptTemp1.setT(this); 815 ptTemp2.setT(pt); 816 if (group.chain.model.isJmolDataFrame) { 817 c.toFractional(ptTemp1, true); 818 c.toFractional(ptTemp2, true); 819 } else { 820 c.toUnitCell(ptTemp1, null); 821 c.toUnitCell(ptTemp2, null); 822 } 823 return ptTemp1.distance(ptTemp2); 824 } 825 setFractionalCoord(int tok, float fValue, boolean asAbsolute)826 void setFractionalCoord(int tok, float fValue, boolean asAbsolute) { 827 SymmetryInterface c = getUnitCell(); 828 if (c != null) 829 c.toFractional(this, asAbsolute); 830 switch (tok) { 831 case T.fux: 832 case T.fracx: 833 x = fValue; 834 break; 835 case T.fuy: 836 case T.fracy: 837 y = fValue; 838 break; 839 case T.fuz: 840 case T.fracz: 841 z = fValue; 842 break; 843 } 844 if (c != null) 845 c.toCartesian(this, asAbsolute); 846 } 847 setFractionalCoordTo(P3 ptNew, boolean asAbsolute)848 void setFractionalCoordTo(P3 ptNew, boolean asAbsolute) { 849 setFractionalCoordPt(this, ptNew, asAbsolute); 850 } 851 setFractionalCoordPt(P3 pt, P3 ptNew, boolean asAbsolute)852 public void setFractionalCoordPt(P3 pt, P3 ptNew, boolean asAbsolute) { 853 pt.setT(ptNew); 854 SymmetryInterface c = getUnitCell(); 855 if (c != null) 856 c.toCartesian(pt, asAbsolute && !group.chain.model.isJmolDataFrame); 857 } 858 isCursorOnTopOf(int xCursor, int yCursor, int minRadius, Atom competitor)859 boolean isCursorOnTopOf(int xCursor, int yCursor, 860 int minRadius, Atom competitor) { 861 int r = sD / 2; 862 if (r < minRadius) 863 r = minRadius; 864 int r2 = r * r; 865 int dx = sX - xCursor; 866 int dx2 = dx * dx; 867 if (dx2 > r2) 868 return false; 869 int dy = sY - yCursor; 870 int dy2 = dy * dy; 871 int dz2 = r2 - (dx2 + dy2); 872 if (dz2 < 0) 873 return false; 874 if (competitor == null) 875 return true; 876 int z = sZ; 877 int zCompetitor = competitor.sZ; 878 int rCompetitor = competitor.sD / 2; 879 if (z < zCompetitor - rCompetitor) 880 return true; 881 int dxCompetitor = competitor.sX - xCursor; 882 int dx2Competitor = dxCompetitor * dxCompetitor; 883 int dyCompetitor = competitor.sY - yCursor; 884 int dy2Competitor = dyCompetitor * dyCompetitor; 885 int r2Competitor = rCompetitor * rCompetitor; 886 int dz2Competitor = r2Competitor - (dx2Competitor + dy2Competitor); 887 return (z - Math.sqrt(dz2) < zCompetitor - Math.sqrt(dz2Competitor)); 888 } 889 890 /* 891 * DEVELOPER NOTE (BH): 892 * 893 * The following methods may not return 894 * correct values until after modelSet.finalizeGroupBuild() 895 * 896 */ 897 getInfo()898 public String getInfo() { 899 return getIdentity(true); 900 } 901 getIdentityXYZ(boolean allInfo, P3 pt)902 public String getIdentityXYZ(boolean allInfo, P3 pt) { 903 pt = (group.chain.model.isJmolDataFrame ? getFractionalCoordPt(!group.chain.model.ms.vwr.g.legacyJavaFloat, false, pt) : this); 904 return getIdentity(allInfo) 905 + " " + PT.formatF(pt.x, 0, 3, true, true) 906 + " " + PT.formatF(pt.y, 0, 3, true, true) 907 + " " + PT.formatF(pt.z, 0, 3, true, true) 908 ; 909 } 910 getIdentity(boolean allInfo)911 String getIdentity(boolean allInfo) { 912 SB info = new SB(); 913 String group3 = getGroup3(true); 914 if (group3 != null && group3.length() > 0 && (!group3.equals("UNK") || group.chain.model.isBioModel)) { 915 info.append("["); 916 info.append(group3); 917 info.append("]"); 918 String seqcodeString = group.getSeqcodeString(); 919 if (seqcodeString != null) 920 info.append(seqcodeString); 921 int chainID = group.chain.chainID; 922 if (chainID != 0 && chainID != 32) { 923 info.append(":"); 924 String s = getChainIDStr(); 925 if (chainID >= 256) 926 s = PT.esc(s); 927 info.append(s); 928 } 929 if (!allInfo) 930 return info.toString(); 931 info.append("."); 932 } 933 info.append(getAtomName()); 934 if (info.length() == 0) { 935 // since atomName cannot be null, this is unreachable 936 info.append(getElementSymbolIso(false)); 937 info.append(" "); 938 info.appendI(getAtomNumber()); 939 } 940 if (altloc != '\0') { 941 info.append("%"); 942 info.appendC(altloc); 943 } 944 if (group.chain.model.ms.mc > 1 && !group.chain.model.isJmolDataFrame) { 945 info.append("/"); 946 info.append(getModelNumberForLabel()); 947 } 948 info.append(" #"); 949 info.appendI(getAtomNumber()); 950 return info.toString(); 951 } 952 953 @Override getGroup3(boolean allowNull)954 public String getGroup3(boolean allowNull) { 955 String group3 = group.getGroup3(); 956 return (allowNull 957 || group3 != null && group3.length() > 0 958 ? group3 : "UNK"); 959 } 960 961 @Override getGroup1(char c0)962 public String getGroup1(char c0) { 963 char c = group.getGroup1(); 964 return (c != '\0' ? "" + c : c0 != '\0' ? "" + c0 : ""); 965 } 966 967 @Override getBioSmilesType()968 public char getBioSmilesType() { 969 return (group.isProtein() ? 'p' 970 : group.isDna() ? 'd' 971 : group.isRna() ? 'r' 972 : group.isCarbohydrate() ? 'c' 973 : ' '); 974 } 975 976 @Override isPurine()977 public boolean isPurine() { 978 return group.isPurine(); 979 } 980 981 @Override isPyrimidine()982 public boolean isPyrimidine() { 983 return group.isPyrimidine(); 984 } 985 986 @Override getResno()987 public int getResno() { 988 return group.getResno(); 989 } 990 isClickable()991 public boolean isClickable() { 992 // certainly if it is not visible, then it can't be clickable 993 return (checkVisible() 994 && clickabilityFlags != 0 995 && ((shapeVisibilityFlags | group.shapeVisibilityFlags) & clickabilityFlags) != 0); 996 } 997 setClickable(int flag)998 public void setClickable(int flag) { 999 if (flag == 0) { 1000 clickabilityFlags = 0; 1001 } else { 1002 clickabilityFlags |= flag; 1003 if (flag != JC.ALPHA_CARBON_VISIBILITY_FLAG) 1004 shapeVisibilityFlags |= flag; 1005 } 1006 } 1007 checkVisible()1008 public boolean checkVisible() { 1009 if (isVisible(ATOM_VISSET)) 1010 return isVisible(ATOM_VISIBLE); 1011 boolean isVis = isVisible(ATOM_INFRAME_NOTHIDDEN); 1012 if (isVis) { 1013 int flags = shapeVisibilityFlags; 1014 // Is its PDB group visible in any way (cartoon, e.g.)? 1015 // An atom is considered visible if its PDB group is visible, even 1016 // if it does not show up itself as part of the structure 1017 // (this will be a difference in terms of *clickability*). 1018 // except BACKBONE -- in which case we only see the lead atoms 1019 if (group.shapeVisibilityFlags != 0 1020 && (group.shapeVisibilityFlags != JC.VIS_BACKBONE_FLAG || isLeadAtom())) 1021 flags |= group.shapeVisibilityFlags; 1022 // We know that (flags & AIM), so now we must remove that flag 1023 // and check to see if any others are remaining. 1024 // Only then is the atom considered visible. 1025 flags &= ATOM_SHAPE_VIS_MASK; 1026 // problem with display of bond-only when not clickable. 1027 // bit of a kludge here. 1028 if (flags == JC.VIS_BOND_FLAG && clickabilityFlags == 0) 1029 flags = 0; 1030 isVis = (flags != 0); 1031 if (isVis) 1032 shapeVisibilityFlags |= ATOM_VISIBLE; 1033 } 1034 shapeVisibilityFlags |= ATOM_VISSET; 1035 return isVis; 1036 1037 } 1038 1039 @Override isLeadAtom()1040 public boolean isLeadAtom() { 1041 return group.isLeadAtom(i); 1042 } 1043 1044 @Override getChainID()1045 public int getChainID() { 1046 return group.chain.chainID; 1047 } 1048 1049 @Override getChainIDStr()1050 public String getChainIDStr() { 1051 return group.chain.getIDStr(); 1052 } 1053 getSurfaceDistance100()1054 public int getSurfaceDistance100() { 1055 return group.chain.model.ms.getSurfaceDistance100(i); 1056 } 1057 getVibrationVector()1058 public Vibration getVibrationVector() { 1059 return group.chain.model.ms.getVibration(i, false); 1060 } 1061 getModulation()1062 public JmolModulationSet getModulation() { 1063 return group.chain.model.ms.getModulation(i); 1064 } 1065 getModelNumberForLabel()1066 public String getModelNumberForLabel() { 1067 return group.chain.model.ms.getModelNumberForAtomLabel(mi); 1068 } 1069 getModelNumber()1070 public int getModelNumber() { 1071 return group.chain.model.ms.getModelNumber(mi) % 1000000; 1072 } 1073 1074 @Override getBioStructureTypeName()1075 public String getBioStructureTypeName() { 1076 return group.getProteinStructureType().getBioStructureTypeName(true); 1077 } 1078 1079 @Override equals(Object obj)1080 public boolean equals(Object obj) { 1081 return (this == obj); 1082 } 1083 1084 @Override hashCode()1085 public int hashCode() { 1086 //this overrides the Point3fi hashcode, which would 1087 //give a different hashcode for an atom depending upon 1088 //its screen location! Bug fix for 11.1.43 Bob Hanson 1089 return i; 1090 } 1091 findAromaticNeighbor(int notAtomIndex)1092 public Atom findAromaticNeighbor(int notAtomIndex) { 1093 if (bonds == null) 1094 return null; 1095 for (int i = bonds.length; --i >= 0; ) { 1096 Bond bondT = bonds[i]; 1097 Atom a = bondT.getOtherAtom(this); 1098 if (bondT.isAromatic() && a.i != notAtomIndex) 1099 return a; 1100 } 1101 return null; 1102 } 1103 1104 /** 1105 * called by isosurface and int comparator via atomProperty() 1106 * and also by getBitsetProperty() 1107 * 1108 * @param tokWhat 1109 * @return int value or Integer.MIN_VALUE 1110 */ atomPropertyInt(int tokWhat)1111 public int atomPropertyInt(int tokWhat) { 1112 switch (tokWhat) { 1113 case T.atomno: 1114 return getAtomNumber(); 1115 case T.seqid: 1116 return getSeqID(); 1117 case T.atomid: 1118 return atomID; 1119 case T.subsystem: 1120 return Math.max(0, altloc - 32); 1121 case T.atomindex: 1122 return i; 1123 case T.bondcount: 1124 return getCovalentBondCount(); 1125 case T.chainno: 1126 return group.chain.chainNo; 1127 case T.color: 1128 return group.chain.model.ms.vwr.gdata.getColorArgbOrGray(colixAtom); 1129 case T.element: 1130 case T.elemno: 1131 return getElementNumber(); 1132 case T.elemisono: 1133 return atomicAndIsotopeNumber; 1134 case T.file: 1135 return group.chain.model.fileIndex + 1; 1136 case T.formalcharge: 1137 return getFormalCharge(); 1138 case T.groupid: 1139 return group.groupID; //-1 if no group 1140 case T.groupindex: 1141 return group.groupIndex; 1142 case T.model: 1143 //integer model number -- could be PDB/sequential adapter number 1144 //or it could be a sequential model in file number when multiple files 1145 return getModelNumber(); 1146 case -T.model: 1147 //float is handled differently 1148 return group.chain.model.ms.modelFileNumbers[mi]; 1149 case T.modelindex: 1150 return mi; 1151 case T.molecule: 1152 return getMoleculeNumber(true); 1153 case T.monomer: 1154 return group.getMonomerIndex() + 1; 1155 case T.occupancy: 1156 return getOccupancy100(); 1157 case T.polymer: 1158 return group.getBioPolymerIndexInModel() + 1; 1159 case T.polymerlength: 1160 return group.getBioPolymerLength(); 1161 case T.radius: 1162 // the comparator uses rasmol radius, unfortunately, for integers 1163 return getRasMolRadius(); 1164 case T.resno: 1165 return getResno(); 1166 case T.site: 1167 return getAtomSite(); 1168 case T.structure: 1169 return group.getProteinStructureType().getId(); 1170 case T.substructure: 1171 return group.getProteinStructureSubType().getId(); 1172 case T.strucno: 1173 return group.getStrucNo(); 1174 case T.symop: 1175 return getSymOp(); 1176 case T.valence: 1177 return getValence(); 1178 } 1179 return 0; 1180 } 1181 getSymOp()1182 int getSymOp() { 1183 return (atomSymmetry == null ? 0 : atomSymmetry.nextSetBit(0) + 1); 1184 } 1185 1186 /** 1187 * called by isosurface and int comparator via atomProperty() and also by 1188 * getBitsetProperty() 1189 * 1190 * @param vwr 1191 * 1192 * @param tokWhat 1193 * @param ptTemp 1194 * @return float value or value*100 (asInt=true) or throw an error if not 1195 * found 1196 * 1197 */ atomPropertyFloat(Viewer vwr, int tokWhat, P3 ptTemp)1198 public float atomPropertyFloat(Viewer vwr, int tokWhat, P3 ptTemp) { 1199 switch (tokWhat) { 1200 case T.adpmax: 1201 return getADPMinMax(true); 1202 case T.adpmin: 1203 return getADPMinMax(false); 1204 case T.atomx: 1205 case T.x: 1206 return x; 1207 case T.atomy: 1208 case T.y: 1209 return y; 1210 case T.atomz: 1211 case T.z: 1212 return z; 1213 case T.dssr: 1214 return group.chain.model.ms.getAtomicDSSRData(i); 1215 case T.backbone: 1216 case T.cartoon: 1217 case T.dots: 1218 case T.ellipsoid: 1219 case T.geosurface: 1220 case T.halo: 1221 case T.meshRibbon: 1222 case T.ribbon: 1223 case T.rocket: 1224 case T.star: 1225 case T.strands: 1226 case T.trace: 1227 return vwr.shm.getAtomShapeValue(tokWhat, group, i); 1228 case T.bondingradius: 1229 return getBondingRadius(); 1230 case T.chemicalshift: 1231 return vwr.getNMRCalculation().getChemicalShift(this); 1232 case T.covalentradius: 1233 return Elements.getCovalentRadius(atomicAndIsotopeNumber); 1234 case T.eta: 1235 case T.theta: 1236 case T.straightness: 1237 return group.getGroupParameter(tokWhat); 1238 case T.fux: 1239 case T.fracx: 1240 return getFractionalCoord(!vwr.g.legacyJavaFloat, 'X', false, ptTemp); 1241 case T.fuy: 1242 case T.fracy: 1243 return getFractionalCoord(!vwr.g.legacyJavaFloat, 'Y', false, ptTemp); 1244 case T.fuz: 1245 case T.fracz: 1246 return getFractionalCoord(!vwr.g.legacyJavaFloat, 'Z', false, ptTemp); 1247 case T.hydrophobicity: 1248 return getHydrophobicity(); 1249 case T.magneticshielding: 1250 return vwr.getNMRCalculation().getMagneticShielding(this); 1251 case T.mass: 1252 return getMass(); 1253 case T.occupancy: 1254 return getOccupancy100() / 100f; 1255 case T.partialcharge: 1256 return getPartialCharge(); 1257 case T.phi: 1258 case T.psi: 1259 case T.omega: 1260 if (group.chain.model.isJmolDataFrame 1261 && group.chain.model.jmolFrameType 1262 .startsWith("plot ramachandran")) { 1263 switch (tokWhat) { 1264 case T.phi: 1265 return getFractionalCoord(!vwr.g.legacyJavaFloat, 'X', false, ptTemp); 1266 case T.psi: 1267 return getFractionalCoord(!vwr.g.legacyJavaFloat, 'Y', false, ptTemp); 1268 case T.omega: 1269 if (group.chain.model.isJmolDataFrame 1270 && group.chain.model.jmolFrameType 1271 .equals("plot ramachandran")) { 1272 float omega = getFractionalCoord(!vwr.g.legacyJavaFloat, 'Z', false, ptTemp) - 180; 1273 return (omega < -180 ? 360 + omega : omega); 1274 } 1275 } 1276 } 1277 return group.getGroupParameter(tokWhat); 1278 case T.radius: 1279 case T.spacefill: 1280 return getRadius(); 1281 case T.screenx: 1282 return (vwr.antialiased ? sX / 2 : sX); 1283 case T.screeny: 1284 return vwr.getScreenHeight() - (vwr.antialiased ? sY / 2 : sY); 1285 case T.screenz: 1286 return (vwr.antialiased ? sZ / 2 : sZ); 1287 case T.selected: 1288 return (vwr.slm.isAtomSelected(i) ? 1 : 0); 1289 case T.surfacedistance: 1290 vwr.ms.getSurfaceDistanceMax(); 1291 return getSurfaceDistance100() / 100f; 1292 case T.temperature: // 0 - 9999 1293 return getBfactor100() / 100f; 1294 case T.unitx: 1295 return getFractionalUnitCoord(!vwr.g.legacyJavaFloat, 'X', ptTemp); 1296 case T.unity: 1297 return getFractionalUnitCoord(!vwr.g.legacyJavaFloat, 'Y', ptTemp); 1298 case T.unitz: 1299 return getFractionalUnitCoord(!vwr.g.legacyJavaFloat, 'Z', ptTemp); 1300 case T.vanderwaals: 1301 return getVanderwaalsRadiusFloat(vwr, VDW.AUTO); 1302 case T.vectorscale: 1303 V3 v = getVibrationVector(); 1304 return (v == null ? 0 : v.length() * vwr.getFloat(T.vectorscale)); 1305 case T.vibx: 1306 return getVib('x'); 1307 case T.viby: 1308 return getVib('y'); 1309 case T.vibz: 1310 return getVib('z'); 1311 case T.modx: 1312 return getVib('X'); 1313 case T.mody: 1314 return getVib('Y'); 1315 case T.modz: 1316 return getVib('Z'); 1317 case T.modo: 1318 return getVib('O'); 1319 case T.modt1: 1320 return getVib('1'); 1321 case T.modt2: 1322 return getVib('2'); 1323 case T.modt3: 1324 return getVib('3'); 1325 case T.volume: 1326 return getVolume(vwr, VDW.AUTO); 1327 case T.fracxyz: 1328 case T.fuxyz: 1329 case T.unitxyz: 1330 case T.screenxyz: 1331 case T.vibxyz: 1332 case T.modxyz: 1333 case T.xyz: 1334 T3 v3 = atomPropertyTuple(vwr, tokWhat, ptTemp); 1335 return (v3 == null ? -1 : v3.length()); 1336 } 1337 return atomPropertyInt(tokWhat); 1338 } 1339 getVib(char ch)1340 public float getVib(char ch) { 1341 return group.chain.model.ms.getVibCoord(i, ch); 1342 } 1343 getNominalMass()1344 public int getNominalMass() { 1345 int mass = getIsotopeNumber(); 1346 return (mass > 0 ? mass : Elements.getNaturalIsotope(getElementNumber())); 1347 } 1348 1349 @Override getMass()1350 public float getMass() { 1351 float mass = getIsotopeNumber(); 1352 return (mass > 0 ? mass : Elements.getAtomicMass(getElementNumber())); 1353 } 1354 atomPropertyString(Viewer vwr, int tokWhat)1355 public String atomPropertyString(Viewer vwr, int tokWhat) { 1356 char ch; 1357 String s; 1358 switch (tokWhat) { 1359 case T.altloc: 1360 ch = altloc; 1361 return (ch == '\0' ? "" : "" + ch); 1362 case T.atomname: 1363 return getAtomName(); 1364 case T.atomtype: 1365 return getAtomType(); 1366 case T.chain: 1367 return getChainIDStr(); 1368 case T.chirality: 1369 return getCIPChirality(true); 1370 case T.ciprule: 1371 return getCIPChiralityRule(); 1372 case T.sequence: 1373 return getGroup1('?'); 1374 case T.seqcode: 1375 s = group.getSeqcodeString(); 1376 return (s == null ? "" : s); 1377 case T.group1: 1378 return getGroup1('\0'); 1379 case T.group: 1380 return getGroup3(false); 1381 case T.element: 1382 return getElementSymbolIso(true); 1383 case T.identify: 1384 return getIdentity(true); 1385 case T.insertion: 1386 ch = group.getInsertionCode(); 1387 return (ch == '\0' ? "" : "" + ch); 1388 case T.label: 1389 case T.format: 1390 s = (String) vwr.shm.getShapePropertyIndex(JC.SHAPE_LABELS, "label", i); 1391 if (s == null) 1392 s = ""; 1393 return s; 1394 case T.structure: 1395 return group.getProteinStructureType().getBioStructureTypeName(false); 1396 case T.substructure: 1397 return group.getProteinStructureSubType().getBioStructureTypeName(false); 1398 case T.strucid: 1399 return group.getStructureId(); 1400 case T.shape: 1401 return vwr.getHybridizationAndAxes(i, null, null, "d"); 1402 case T.symbol: 1403 return getElementSymbolIso(false); 1404 case T.symmetry: 1405 return getSymmetryOperatorList(true); 1406 } 1407 return ""; 1408 } 1409 1410 /** 1411 * Determine R/S chirality at this position; non-H atoms only; cached in formalChargeAndFlags 1412 * @param doCalculate 1413 * 1414 * @return one of "", "R", "S", "E", "Z", "r", "s", "?" 1415 */ 1416 @Override getCIPChirality(boolean doCalculate)1417 public String getCIPChirality(boolean doCalculate) { 1418 int flags = (formalChargeAndFlags & CIP_CHIRALITY_MASK) >> CIP_CHIRALITY_OFFSET; 1419 if (flags == 0 && atomicAndIsotopeNumber > 1 && doCalculate) { 1420 flags = group.chain.model.ms.getAtomCIPChiralityCode(this); 1421 formalChargeAndFlags |= ((flags == 0 ? JC.CIP_CHIRALITY_NONE : flags) << CIP_CHIRALITY_OFFSET); 1422 } 1423 return JC.getCIPChiralityName(flags); 1424 } 1425 getCIPChiralityRule()1426 public String getCIPChiralityRule() { 1427 String rs = getCIPChirality(true); 1428 int flags = (rs.length() == 0 ? -1 : (formalChargeAndFlags & CIP_CHIRALITY_RULE_MASK) >> CIP_CHIRALITY_RULE_OFFSET); 1429 return JC.getCIPRuleName(flags + 1); 1430 } 1431 1432 /** 1433 * 1434 * @param c [0:unknown; 3:none; 1: R; 2: S; 5: Z; 6: E; 9: M, 10: P, +r,s 1435 */ 1436 @Override setCIPChirality(int c)1437 public void setCIPChirality(int c) { 1438 formalChargeAndFlags = (formalChargeAndFlags & ~CIP_MASK) 1439 | (c << CIP_CHIRALITY_OFFSET); 1440 } 1441 1442 @Override getCIPChiralityCode()1443 public int getCIPChiralityCode() { 1444 return (formalChargeAndFlags & CIP_CHIRALITY_MASK) >> CIP_CHIRALITY_OFFSET; 1445 } 1446 1447 @Override getInsertionCode()1448 public char getInsertionCode() { 1449 return group.getInsertionCode(); 1450 } 1451 atomPropertyTuple(Viewer vwr, int tok, P3 ptTemp)1452 public T3 atomPropertyTuple(Viewer vwr, int tok, P3 ptTemp) { 1453 switch (tok) { 1454 case T.coord: 1455 return P3.newP(this); 1456 case T.fracxyz: 1457 return getFractionalCoordPt(!vwr.g.legacyJavaFloat, false, ptTemp); // was !group.chain.model.isJmolDataFrame 1458 case T.fuxyz: 1459 return getFractionalCoordPt(!vwr.g.legacyJavaFloat, false, ptTemp); 1460 case T.unitxyz: 1461 return (group.chain.model.isJmolDataFrame ? getFractionalCoordPt(!vwr.g.legacyJavaFloat, false, ptTemp) 1462 : getFractionalUnitCoordPt(!vwr.g.legacyJavaFloat, false, ptTemp)); 1463 case T.screenxyz: 1464 return P3.new3(vwr.antialiased ? sX / 2 : sX, vwr.getScreenHeight() - (vwr.antialiased ? sY / 2 : sY), vwr.antialiased ? sZ / 2 : sZ); 1465 case T.vibxyz: 1466 return getVibrationVector(); 1467 case T.modxyz: 1468 JmolModulationSet ms = getModulation(); 1469 return (ms == null ? null : ms.getV3()); 1470 case T.xyz: 1471 return this; 1472 case T.color: 1473 return CU.colorPtFromInt( 1474 group.chain.model.ms.vwr.gdata.getColorArgbOrGray(colixAtom), 1475 ptTemp); 1476 } 1477 return null; 1478 } 1479 1480 @Override getOffsetResidueAtom(String name, int offset)1481 public int getOffsetResidueAtom(String name, int offset) { 1482 // used by DSSP and SMILES 1483 return group.getAtomIndex(name, offset); 1484 } 1485 1486 @Override isCrossLinked(Node node)1487 public boolean isCrossLinked(Node node) { 1488 return group.isCrossLinked(((Atom) node).group); 1489 } 1490 1491 /** 1492 * Used by SMILES to get vector of cross-links 1493 */ 1494 @Override getCrossLinkVector(Lst<Integer> vReturn, boolean crosslinkCovalent, boolean crosslinkHBond)1495 public boolean getCrossLinkVector(Lst<Integer> vReturn, boolean crosslinkCovalent, boolean crosslinkHBond) { 1496 return group.getCrossLinkVector(vReturn, crosslinkCovalent, crosslinkHBond); 1497 } 1498 1499 @Override toString()1500 public String toString() { 1501 return getInfo(); 1502 } 1503 1504 @Override findAtomsLike(String atomExpression)1505 public BS findAtomsLike(String atomExpression) { 1506 // for SMARTS searching 1507 return group.chain.model.ms.vwr.getAtomBitSet(atomExpression); 1508 } 1509 getUnitID(int flags)1510 public String getUnitID(int flags) { 1511 Model m = group.chain.model; 1512 return (m.isBioModel ? ((BioModel) m).getUnitID(this, flags) : ""); 1513 } 1514 1515 @Override getFloatProperty(String property)1516 public float getFloatProperty(String property) { 1517 Object data = group.chain.model.ms.vwr.getDataObj(property, null, 1518 JmolDataManager.DATA_TYPE_AF); 1519 float f = Float.NaN; 1520 if (data != null) { 1521 try { 1522 f = ((float[]) data)[i]; 1523 } catch (Exception e) { 1524 } 1525 } 1526 return f; 1527 } 1528 1529 @Override modelIsRawPDB()1530 public boolean modelIsRawPDB() { 1531 Model m = group.chain.model; 1532 return (m.isBioModel && !m.isPdbWithMultipleBonds && m.hydrogenCount == 0); 1533 } 1534 1535 } 1536