Package org.jmol.modelset

Source Code of org.jmol.modelset.LabelToken

/* $RCSfile$
* $Author: hansonr $
* $Date: 2007-10-14 12:33:20 -0500 (Sun, 14 Oct 2007) $
* $Revision: 8408 $

*
* Copyright (C) 2003-2005  The Jmol Development Team
*
* Contact: jmol-developers@lists.sf.net
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jmol.modelset;

import java.util.Enumeration;
import java.util.Hashtable;

import javax.vecmath.Tuple3f;

import org.jmol.util.TextFormat;
import org.jmol.script.Token;
import org.jmol.viewer.Viewer;

public class LabelToken {
 
  /*
   * by Bob Hanson, 5/28/2009
   *
   * a compiler for the atom label business.
   *
   * Prior to this, once for every atom, twice for every bond, and 2-4 times for every
   * measurement we were scanning the format character by character. And if data were
   * involved, then calls were made for every atom to find the data set and return its
   * value. Now you can still do that, but the Jmol code doesn't.
   *
   * Instead, we now first compile a set of tokens -- either pure text or some
   * sort of %xxxx business. Generally we would alternate between these, so the
   * compiler is set up to initialize an array that has 2n+1 elements, where n is the
   * number of % signs in the string. This is guaranteed to be more than really necessary.
   *
   * Because we are working with tokens, we can go beyond the limiting A-Za-z business
   * that we had before. That still works, but now we can have any standard token be
   * used in brackets:
   *
   *   %n.m[xxxxx]
   *
   * This complements the
   *
   *   %n.m{xxxxx}
   *  
   * used for data. The brackets make for a nice-looking format:
   *
   *
   *  print {*}.bonds.label("%6[atomName]1 - %6[atomName]2  %3ORDER  %6.2LENGTH")
   *
   * [Note that the %ORDER and %LENGTH variables are bond labeling options, and
   *  the 1 and 2 after %[xxx] indicate which atom in involved.
   *
   *
   */

  private String text;
  private String key;
  private float[] data;
  private int tok;
  private int pt = -1;
  private char ch1;
  private int width;
  private int precision = Integer.MAX_VALUE;
  private boolean alignLeft;
  private boolean zeroPad;
  private boolean intAsFloat;

  // do not change array order without changing string order as well
  // new tokens can be added to the list at the end
  // and then also added in appendTokenValue()
  // and also in Eval, to atomProperty()
 
  final private static String labelTokenParams = "AaBbCcDEefGgIiLlMmNnoPpQqRrSsTtUuVvWXxYyZz%%%gqW";
  final private static int[] labelTokenIds = {
  /* 'A' */Token.altloc,
  /* 'a' */Token.atomname,
  /* 'B' */Token.atomtype,
  /* 'b' */Token.temperature,
  /* 'C' */Token.formalcharge,
  /* 'c' */Token.chain,
  /* 'D' */Token.atomindex,
  /* 'E' */Token.insertion,
  /* 'e' */Token.element,
  /* 'f' */Token.phi,
  /* 'G' */Token.groupindex,
  /* 'g' */'g', //getSelectedGroupIndexWithinChain()
  /* 'I' */Token.ionic,
  /* 'i' */Token.atomno,
  /* 'L' */Token.polymerlength,
  /* 'l' */Token.elemno,
  /* 'M' */Token.model,
  /* 'm' */Token.group1,
  /* 'N' */Token.molecule,
  /* 'n' */Token.group,
  /* 'o' */Token.symmetry,
  /* 'P' */Token.partialcharge,
  /* 'p' */Token.psi,
  /* 'Q' */'Q'//occupancy 0.0 to 1.0
  /* 'q' */Token.occupancy,
  /* 'R' */Token.resno,
  /* 'r' */'r',
  /* 'S' */Token.site,
  /* 's' */Token.chain,
  /* 'T' */Token.straightness,
  /* 't' */Token.temperature,
  /* 'U' */Token.identify,
  /* 'u' */Token.surfacedistance,
  /* 'V' */Token.vanderwaals,
  /* 'v' */Token.vibxyz,
  /* 'W' */'W',   // identifier and XYZ coord
  /* 'X' */Token.fracx,
  /* 'x' */Token.atomx,
  /* 'Y' */Token.fracy,
  /* 'y' */Token.atomy,
  /* 'Z' */Token.fracz,
  /* 'z' */Token.atomz,

  // not having letter equivalents:
 
           //new for Jmol 11.9.5:
           Token.backbone,
           Token.cartoon,
           Token.dots,
           Token.ellipsoid,
           Token.geosurface,
           Token.halo,
           Token.meshRibbon,
           Token.ribbon,
           Token.rocket,
           Token.star,
           Token.strands,
           Token.trace,

           Token.adpmax,
           Token.adpmin,
           Token.atomid,
           Token.bondcount,
           Token.color,
           Token.groupid,
           Token.covalent,
           Token.file,
           Token.format,
           Token.label,
           Token.modelindex,
           Token.eta,
           Token.omega,
           Token.polymer,
           Token.property,
           Token.radius,
           Token.selected,
           Token.sequence,
           Token.spacefill,
           Token.structure,
           Token.substructure,
           Token.strucno,
           Token.strucid,
           Token.symbol,
           Token.theta,
           Token.unitx,
           Token.unity,
           Token.unitz,
           Token.valence,
           Token.vibx,
           Token.viby,
           Token.vibz,
           Token.volume,
           Token.unitxyz,
           Token.fracxyz,
           Token.xyz,
           Token.fuxyz,
           Token.fux,
           Token.fuy,
           Token.fuz,
          
  };

  private static boolean isLabelPropertyTok(int tok) {
    for (int i = labelTokenIds.length; --i >= 0;)
      if (labelTokenIds[i] == tok)
        return true;
    return false;
  }

  private final static String twoCharLabelTokenParams = "fuv";

  private final static int[] twoCharLabelTokenIds = { Token.fracx, Token.fracy,
      Token.fracz, Token.unitx, Token.unity, Token.unitz, Token.vibx,
      Token.viby, Token.vibz, };

  public static final String STANDARD_LABEL = "%[identify]";

  private LabelToken(String text) {
    this.text = text;
  }

  private LabelToken(int pt) {
    this.pt = pt;
  }

  public static LabelToken[] compile(Viewer viewer, String strFormat, char chAtom, Hashtable htValues) {
    if (strFormat.indexOf("%") < 0 || strFormat.length() < 2)
      return new LabelToken[] { new LabelToken(strFormat) };
    int n = 0;
    int ich = -1;
    int cch = strFormat.length();
    while (++ich < cch && (ich = strFormat.indexOf('%', ich)) >= 0)
      n++;
    LabelToken[] tokens = new LabelToken[n * 2 + 1];
    int ichPercent;
    int i = 0;
    for (ich = 0; (ichPercent = strFormat.indexOf('%', ich)) >= 0;) {
      if (ich != ichPercent)
        tokens[i++] = new LabelToken(strFormat.substring(ich, ichPercent));
      LabelToken lt = tokens[i++] = new LabelToken(ichPercent);
      viewer.autoCalculate(lt.tok);
      ich = setToken(viewer, strFormat, lt, cch, chAtom, htValues);
    }
    if (ich < cch)
      tokens[i++] = new LabelToken(strFormat.substring(ich));
    return tokens;
  }

  private static int setToken(Viewer viewer, String strFormat, LabelToken lt,
                              int cch, int chAtom, Hashtable htValues) {
    int ich = lt.pt + 1;
    char ch;
    if (strFormat.charAt(ich) == '-') {
      lt.alignLeft = true;
      ++ich;
    }
    if (ich < cch && strFormat.charAt(ich) == '0') {
      lt.zeroPad = true;
      ++ich;
    }
    while (ich < cch && Character.isDigit(ch = strFormat.charAt(ich))) {
      lt.width = (10 * lt.width) + (ch - '0');
      ++ich;
    }
    lt.precision = Integer.MAX_VALUE;
    boolean isNegative = false;
    if (ich < cch && strFormat.charAt(ich) == '.') {
      ++ich;
      if (ich < cch && (ch = strFormat.charAt(ich)) == '-') {
        isNegative = true;
        ++ich;
      }
      if (ich < cch && Character.isDigit(ch = strFormat.charAt(ich))) {
        lt.precision = ch - '0';
        if (isNegative)
          lt.precision = -1 - lt.precision;
        ++ich;
      }
    }
    if (ich < cch && htValues != null) {
      Enumeration keys = htValues.keys();
      while (keys.hasMoreElements()) {
        String key = (String) keys.nextElement();
        if (strFormat.indexOf(key) == ich) {
          lt.key = key;
          return ich + key.length();
        }
      }
    }
    if (ich < cch)
      switch (ch = strFormat.charAt(ich++)) {
      case '%':
        lt.text = "%";
        return ich;
      case '[':
        int ichClose = strFormat.indexOf(']', ich);
        if (ichClose < ich) {
          ich = cch;
          break;
        }
        String propertyName = strFormat.substring(ich, ichClose).toLowerCase();
        if (propertyName.startsWith("property_")) {
          lt.text = propertyName;
          lt.tok = Token.data;
          lt.data = viewer.getDataFloat(lt.text);
        } else {
          Token token = Token.getTokenFromName(propertyName);
          if (token != null && isLabelPropertyTok(token.tok))
            lt.tok = token.tok;
        }
        ich = ichClose + 1;
        break;
      case '{': // client property name
        int ichCloseBracket = strFormat.indexOf('}', ich);
        if (ichCloseBracket < ich) {
          ich = cch;
          break;
        }
        lt.text = strFormat.substring(ich, ichCloseBracket);
        lt.tok = Token.data;
        lt.data = viewer.getDataFloat(lt.text);
        ich = ichCloseBracket + 1;
        break;
      default:
        int i,
        i1;
        if (ich < cch && (i = twoCharLabelTokenParams.indexOf(ch)) >= 0
            && (i1 = "xyz".indexOf(strFormat.charAt(ich))) >= 0) {
          lt.tok = twoCharLabelTokenIds[i * 3 + i1];
          ich++;
        } else if ((i = labelTokenParams.indexOf(ch)) >= 0) {
          lt.tok = labelTokenIds[i];
        }
      }
    lt.text = strFormat.substring(lt.pt, ich);
    if (ich < cch && chAtom != '\0'
        && Character.isDigit(ch = strFormat.charAt(ich))) {
      ich++;
      lt.ch1 = ch;
      if (ch != chAtom && chAtom != '\1')
        lt.tok = 0;
    }
    return ich;
  }

  //////////// label formatting for atoms, bonds, and measurements ///////////

  public static String formatLabel(Viewer viewer, Atom atom, String strFormat) {
    return formatLabel(viewer, atom, strFormat, null, '\0', null);
  }

  public static String formatLabel(Viewer viewer, Atom atom, String strFormat, LabelToken[] tokens, char chAtom, int[]indices) {
    if (atom == null || tokens == null && (strFormat == null || strFormat.length() == 0))
        return null;
    StringBuffer strLabel = (chAtom > '0' ? null : new StringBuffer());
    if (tokens == null)
      tokens = compile(viewer, strFormat, chAtom, null);
    for (int i = 0; i < tokens.length; i++) {
      LabelToken t = tokens[i];
      if (t == null)
        break;
      if (chAtom > '0' && t.ch1 != chAtom)
        continue;
      if (t.tok <= 0 || t.key != null) {
        if (strLabel !=  null) {
          strLabel.append(t.text);
          if (t.ch1 != '\0')
            strLabel.append(t.ch1);
        }
      } else {
        appendAtomTokenValue(viewer, atom, t, strLabel, indices);
      }
    }
    return (strLabel == null ? null : strLabel.toString().intern());
  }
 
  private static void appendAtomTokenValue(Viewer viewer, Atom atom, LabelToken t,
                                           StringBuffer strLabel, int[] indices) {
    String strT = null;
    float floatT = Float.NaN;
    Tuple3f ptT = null;
    try {
      switch (t.tok) {
     
      // special cases only for labels
     
      case Token.atomindex:
        strT = ""
            + (indices == null ? atom.index : indices[atom.index]);
        break;
      case Token.color:
        ptT = Atom.atomPropertyTuple(atom, t.tok);
        break;
      case Token.data:
        floatT = (t.data != null ? t.data[atom.index] : Float.NaN);
        break;
      case Token.formalcharge:
        int formalCharge = atom.getFormalCharge();
        if (formalCharge > 0)
          strT = "" + formalCharge + "+";
        else if (formalCharge < 0)
          strT = "" + -formalCharge + "-";
        else
          strT = "";
        break;
      case 'g':
        strT = "" + atom.getSelectedGroupIndexWithinChain();
        break;
      case Token.model:
        strT = atom.getModelNumberForLabel();
        break;
      case Token.occupancy:
        strT = "" + Atom.atomPropertyInt(atom, t.tok);
        break;
      case 'Q':
        floatT = atom.getOccupancy100() / 100f;
        break;
      case Token.radius:
        floatT = Atom.atomPropertyFloat(viewer, atom, t.tok);
        break;
      case 'r':
        strT = atom.getSeqcodeString();
        break;
      case Token.strucid:
        strT = atom.getStructureId();
        break;
      case Token.strucno:
        int id = atom.getStrucNo();
        strT = (id <= 0 ? "" : "" + id);
        break;
      case Token.straightness:
        floatT = atom.getGroupParameter(Token.straightness);
        if (Float.isNaN(floatT))
          strT = "null";
        break;
      case Token.structure:
      case Token.substructure:
        strT = Atom.atomPropertyString(atom, t.tok);
        break;
      case 'W':
        strT = atom.getIdentityXYZ(false);
        break;
       
      // standard
       
      default:
        switch (t.tok & Token.PROPERTYFLAGS) {
        case Token.intproperty:
          if (t.intAsFloat)
            floatT = Atom.atomPropertyInt(atom, t.tok);
          else
            strT = "" + Atom.atomPropertyInt(atom, t.tok);
          break;
        case Token.floatproperty:
          floatT = Atom.atomPropertyFloat(viewer, atom, t.tok);
          break;
        case Token.strproperty:
          strT = Atom.atomPropertyString(atom, t.tok);
          break;
        case Token.atomproperty:
          ptT = Atom.atomPropertyTuple(atom, t.tok);
        default:
          // any dual case would be here -- must handle specially
        }
      }
    } catch (IndexOutOfBoundsException ioobe) {
      floatT = Float.NaN;
      strT = null;
      ptT = null;
    }
    strT = t.format(floatT, strT, ptT);
    if (strLabel == null)
      t.text = strT;
    else
      strLabel.append(strT);
  }

 
  public static Hashtable getBondLabelValues() {
    Hashtable htValues = new Hashtable();
    htValues.put("#", "");
    htValues.put("ORDER", "");
    htValues.put("TYPE", "");
    htValues.put("LENGTH", new Float(0));
    htValues.put("ENERGY", new Float(0));
    return htValues;
  }

  public static String formatLabel(Viewer viewer, Bond bond,
                                   LabelToken[] tokens, Hashtable values,
                                   int[] indices) {
    values.put("#", "" + (bond.index + 1));
    values.put("ORDER", "" + bond.getOrderNumberAsString());
    values.put("TYPE", bond.getOrderName());
    values.put("LENGTH", new Float(bond.atom1.distance(bond.atom2)));
    values.put("ENERGY", new Float(bond.getEnergy()));
    setValues(tokens, values);
    formatLabel(viewer, bond.atom1, null, tokens, '1', indices);
    formatLabel(viewer, bond.atom2, null, tokens, '2', indices);
    return getLabel(tokens);
  }

  public static String formatLabel(Viewer viewer, Measurement measurement,
                                   String label, float value, String units) {
    Hashtable htValues = new Hashtable();
    htValues.put("#", "" + (measurement.getIndex() + 1));
    htValues.put("VALUE", new Float(value));
    htValues.put("UNITS", units);
    LabelToken[] tokens = compile(viewer, label, '\1', htValues);
    setValues(tokens, htValues);
    Atom[] atoms = measurement.modelSet.atoms;
    int[] indices = measurement.getCountPlusIndices();
    for (int i = indices[0]; i >= 1; --i)
      if (indices[i] >= 0)
        formatLabel(viewer, atoms[indices[i]], null, tokens, (char) ('0' + i),
            null);
    label = getLabel(tokens);
    return (label == null ? "" : label);
  }

  private String format(float floatT, String strT, Tuple3f ptT) {
    if (!Float.isNaN(floatT)) {
      return TextFormat.format(floatT, width, precision, alignLeft, zeroPad);
    } else if (strT != null) {
      return TextFormat.format(strT, width, precision, alignLeft, zeroPad);
    } else if (ptT != null) {
      if (width == 0 && precision == Integer.MAX_VALUE) {
        width = 6;
        precision = 2;
      }
      return TextFormat.format(ptT.x, width, precision, false, false)
      + TextFormat.format(ptT.y, width, precision, false, false)
      + TextFormat.format(ptT.z, width, precision, false, false);
    } else {
      return text;
    }
  }

  public static void setValues(LabelToken[] tokens, Hashtable values) {
    for (int i = 0; i < tokens.length; i++) {
      LabelToken lt = tokens[i];
      if (lt == null)
        break;
      if (lt.key == null)
        continue;
      Object value = values.get(lt.key);
        lt.text = (value instanceof Float ?
            lt.format(((Float)value).floatValue(), null, null)
            : lt.format(Float.NaN, (String) value, null));
    }   
  }

  public static String getLabel(LabelToken[] tokens) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < tokens.length; i++) {
      LabelToken lt = tokens[i];
      if (lt == null)
        break;
      sb.append(lt.text);
    }
    return sb.toString();
  }

}
TOP

Related Classes of org.jmol.modelset.LabelToken

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.