1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2007-10-14 12:33:20 -0500 (Sun, 14 Oct 2007) $ 4 * $Revision: 8408 $ 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 java.util.Hashtable; 29 import java.util.Map; 30 31 32 33 import javajs.util.AU; 34 import javajs.util.Lst; 35 import javajs.util.P3; 36 import javajs.util.PT; 37 import javajs.util.SB; 38 import javajs.util.T3; 39 40 import org.jmol.api.JmolDataManager; 41 import org.jmol.script.SV; 42 import org.jmol.script.T; 43 import org.jmol.util.Edge; 44 import org.jmol.viewer.JC; 45 import org.jmol.viewer.Viewer; 46 47 48 public class LabelToken { 49 50 /* 51 * by Bob Hanson, 5/28/2009 52 * 53 * a compiler for the atom label business. 54 * 55 * Prior to this, once for every atom, twice for every bond, and 2-4 times for every 56 * measurement we were scanning the format character by character. And if data were 57 * involved, then calls were made for every atom to find the data set and return its 58 * value. Now you can still do that, but the Jmol code doesn't. 59 * 60 * Instead, we now first compile a set of tokens -- either pure text or some 61 * sort of %xxxx business. Generally we would alternate between these, so the 62 * compiler is set up to initialize an array that has 2n+1 elements, where n is the 63 * number of % signs in the string. This is guaranteed to be more than really necessary. 64 * 65 * Because we are working with tokens, we can go beyond the limiting A-Za-z business 66 * that we had before. That still works, but now we can have any standard token be 67 * used in brackets: 68 * 69 * %n.m[xxxxx] 70 * 71 * This complements the 72 * 73 * %n.m{xxxxx} 74 * 75 * used for data. The brackets make for a nice-looking format: 76 * 77 * 78 * print {*}.bonds.label("%6[atomName]1 - %6[atomName]2 %3ORDER %6.2LENGTH") 79 * 80 * [Note that the %ORDER and %LENGTH variables are bond labeling options, and 81 * the 1 and 2 after %[xxx] indicate which atom in involved. 82 * 83 * 84 */ 85 86 private String text; 87 private String key; 88 private Object data; 89 private int tok; 90 private int pt = -1; 91 private char ch1 = '\0'; 92 private int width; 93 private int precision = Integer.MAX_VALUE; 94 private boolean alignLeft; 95 private boolean zeroPad; 96 private boolean intAsFloat; 97 98 // do not change array order without changing string order as well 99 // new tokens can be added to the list at the end 100 // and then also added in appendTokenValue() 101 // and also in Eval, to atomProperty() 102 103 final private static String labelTokenParams = "AaBbCcDEefGgIiLlMmNnOoPpQqRrSsTtUuVvWXxxYyyZzz%%%gqW"; 104 final private static int[] labelTokenIds = { 105 /* 'A' */T.altloc, 106 /* 'a' */T.atomname, 107 /* 'B' */T.atomtype, 108 /* 'b' */T.temperature, 109 /* 'C' */T.formalcharge, 110 /* 'c' */T.chain, 111 /* 'D' */T.atomindex, 112 /* 'E' */T.insertion, 113 /* 'e' */T.element, 114 /* 'f' */T.phi, 115 /* 'G' */T.groupindex, 116 /* 'g' */T.monomer, //getSelectedGroupIndexWithinChain() 117 /* 'I' */T.bondingradius, 118 /* 'i' */T.atomno, 119 /* 'L' */T.polymerlength, 120 /* 'l' */T.elemno, 121 /* 'M' */T.model, 122 /* 'm' */T.group1, 123 /* 'N' */T.molecule, 124 /* 'n' */T.group, 125 /* 'O' */79, // all symmetry operators 126 /* 'o' */T.symmetry, 127 /* 'P' */T.partialcharge, 128 /* 'p' */T.psi, 129 /* 'Q' */81, //occupancy 0.0 to 1.0 130 /* 'q' */T.occupancy, 131 /* 'R' */T.resno, 132 /* 'r' */T.seqcode, 133 /* 'S' */T.site, 134 /* 's' */T.chain, 135 /* 'T' */T.straightness, 136 /* 't' */T.temperature, 137 /* 'U' */T.identify, 138 /* 'u' */T.surfacedistance, 139 /* 'V' */T.vanderwaals, 140 /* 'v' */T.vibxyz, 141 /* 'W' */T.w, // identifier and XYZ coord 142 /* 'X' */T.fracx, 143 /* 'x' */T.atomx, 144 /* 'x' */T.x, 145 /* 'Y' */T.fracy, 146 /* 'y' */T.atomy, 147 /* 'y' */T.y, 148 /* 'Z' */T.fracz, 149 /* 'z' */T.atomz, 150 /* 'z' */T.z, 151 152 // not having letter equivalents: 153 154 //new for Jmol 11.9.5: 155 T.backbone, T.cartoon, T.dots, T.ellipsoid, 156 T.geosurface, T.halo, T.meshRibbon, T.ribbon, 157 T.rocket, T.star, T.strands, T.trace, 158 159 T.adpmax, T.adpmin, T.atomid, T.bondcount, T.color, 160 T.groupid, T.covalentradius, T.file, T.format, T.label, 161 T.mass, T.modelindex, T.eta, T.omega, T.polymer, T.property, 162 T.radius, T.selected, T.shape, T.sequence, 163 T.spacefill, T.structure, T.substructure, T.strucno, 164 T.strucid, T.symbol, T.theta, T.unitx, T.unity, 165 T.unitz, T.valence, T.vectorscale, T.vibx, T.viby, T.vibz, 166 T.volume, T.unitxyz, T.fracxyz, T.xyz, T.fuxyz, 167 T.fux, T.fuy, T.fuz, T.hydrophobicity, T.screenx, 168 T.screeny, T.screenz, T.screenxyz, // added in 12.3.30 169 T.magneticshielding, T.chemicalshift, T.chainno, T.seqid, 170 T.modx, T.mody, T.modz, T.modo, T.modxyz, T.symop, 171 T.nbo, // added in 14.8.2 172 T.chirality, // added in 14.11.4 173 T.ciprule // added in 14.17.0 174 }; 175 LabelToken()176 public LabelToken() { 177 // for access to static methods without preloading JavaScript 178 } set(String text, int pt)179 private LabelToken set(String text, int pt) { 180 this.text = text; 181 this.pt = pt; 182 return this; 183 } 184 isLabelPropertyTok(int tok)185 private static boolean isLabelPropertyTok(int tok) { 186 for (int i = labelTokenIds.length; --i >= 0;) 187 if (labelTokenIds[i] == tok) 188 return true; 189 return false; 190 } 191 192 public static final String STANDARD_LABEL = "%[identify]"; 193 194 private final static String twoCharLabelTokenParams = "fuv"; 195 196 private final static int[] twoCharLabelTokenIds = { T.fracx, T.fracy, 197 T.fracz, T.unitx, T.unity, T.unitz, T.vibx, 198 T.viby, T.vibz, }; 199 200 /** 201 * Compiles a set of tokens for each primitive element of a 202 * label. This is the efficient way to create a set of labels. 203 * 204 * @param vwr 205 * @param strFormat 206 * @param chAtom 207 * @param htValues 208 * @return array of tokens 209 */ compile(Viewer vwr, String strFormat, char chAtom, Map<String, Object> htValues)210 public static LabelToken[] compile(Viewer vwr, String strFormat, 211 char chAtom, Map<String, Object> htValues) { 212 if (strFormat == null || strFormat.length() == 0) 213 return null; 214 if (strFormat.indexOf("%") < 0 || strFormat.length() < 2) 215 return new LabelToken[] { new LabelToken().set(strFormat, -1) }; 216 int n = 0; 217 int ich = -1; 218 int cch = strFormat.length(); 219 while (++ich < cch && (ich = strFormat.indexOf('%', ich)) >= 0) 220 n++; 221 LabelToken[] tokens = new LabelToken[n * 2 + 1]; 222 int ichPercent; 223 int i = 0; 224 for (ich = 0; (ichPercent = strFormat.indexOf('%', ich)) >= 0;) { 225 if (ich != ichPercent) 226 tokens[i++] = new LabelToken().set(strFormat.substring(ich, ichPercent), -1); 227 LabelToken lt = tokens[i++] = new LabelToken().set(null, ichPercent); 228 vwr.autoCalculate(lt.tok, null); 229 ich = setToken(vwr, strFormat, lt, cch, chAtom, htValues); 230 } 231 if (ich < cch) 232 tokens[i++] = new LabelToken().set(strFormat.substring(ich), -1); 233 return tokens; 234 } 235 236 //////////// label formatting for atoms, bonds, and measurements /////////// 237 formatLabel(Viewer vwr, Atom atom, String strFormat, P3 ptTemp)238 public String formatLabel(Viewer vwr, Atom atom, String strFormat, P3 ptTemp) { 239 return (strFormat == null || strFormat.length() == 0 ? null 240 : formatLabelAtomArray(vwr, atom, compile(vwr, strFormat, '\0', null), 241 '\0', null, ptTemp)); 242 } 243 244 /** 245 * returns a formatted string based on the precompiled label tokens 246 * 247 * @param vwr 248 * @param atom 249 * @param tokens 250 * @param chAtom 251 * @param indices 252 * @param ptTemp 253 * @return formatted string 254 */ formatLabelAtomArray(Viewer vwr, Atom atom, LabelToken[] tokens, char chAtom, int[] indices, P3 ptTemp)255 public static String formatLabelAtomArray(Viewer vwr, Atom atom, 256 LabelToken[] tokens, char chAtom, 257 int[] indices, P3 ptTemp) { 258 if (atom == null) 259 return null; 260 SB strLabel = (chAtom > '0' ? null : new SB()); 261 if (tokens != null) 262 for (int i = 0; i < tokens.length; i++) { 263 LabelToken t = tokens[i]; 264 if (t == null) 265 break; 266 if (chAtom > '0' && t.ch1 != chAtom) 267 continue; 268 if (t.tok <= 0 || t.key != null) { 269 if (strLabel != null) { 270 strLabel.append(t.text); 271 if (t.ch1 != '\0') 272 strLabel.appendC(t.ch1); 273 } 274 } else { 275 appendAtomTokenValue(vwr, atom, t, strLabel, indices, ptTemp); 276 } 277 } 278 return (strLabel == null ? null : strLabel.toString().intern()); 279 } 280 getBondLabelValues()281 public static Map<String, Object> getBondLabelValues() { 282 Map<String, Object> htValues = new Hashtable<String, Object>(); 283 htValues.put("#", ""); 284 htValues.put("ORDER", ""); 285 htValues.put("TYPE", ""); 286 htValues.put("LENGTH", Float.valueOf(0)); 287 htValues.put("ENERGY", Float.valueOf(0)); 288 return htValues; 289 } 290 formatLabelBond(Viewer vwr, Bond bond, LabelToken[] tokens, Map<String, Object> values, int[] indices, P3 ptTemp)291 public static String formatLabelBond(Viewer vwr, Bond bond, 292 LabelToken[] tokens, 293 Map<String, Object> values, int[] indices, P3 ptTemp) { 294 values.put("#", "" + (bond.index + 1)); 295 values.put("ORDER", "" + Edge.getBondOrderNumberFromOrder(bond.order)); 296 values.put("TYPE", Edge.getBondOrderNameFromOrder(bond.order)); 297 values.put("LENGTH", Float.valueOf(bond.atom1.distance(bond.atom2))); 298 values.put("ENERGY", Float.valueOf(bond.getEnergy())); 299 setValues(tokens, values); 300 formatLabelAtomArray(vwr, bond.atom1, tokens, '1', indices, ptTemp); 301 formatLabelAtomArray(vwr, bond.atom2, tokens, '2', indices, ptTemp); 302 return getLabel(tokens); 303 } 304 formatLabelMeasure(Viewer vwr, Measurement m, String label, float value, String units)305 public static String formatLabelMeasure(Viewer vwr, Measurement m, 306 String label, float value, String units) { 307 Map<String, Object> htValues = new Hashtable<String, Object>(); 308 htValues.put("#", "" + (m.index + 1)); 309 htValues.put("VALUE", Float.valueOf(value)); 310 htValues.put("UNITS", units); 311 LabelToken[] tokens = compile(vwr, label, '\1', htValues); 312 if (tokens == null) 313 return ""; 314 setValues(tokens, htValues); 315 Atom[] atoms = m.ms.at; 316 int[] indices = m.countPlusIndices; 317 for (int i = indices[0]; i >= 1; --i) 318 if (indices[i] >= 0) 319 formatLabelAtomArray(vwr, atoms[indices[i]], tokens, (char) ('0' + i), null, null); 320 label = getLabel(tokens); 321 return (label == null ? "" : label); 322 } 323 setValues(LabelToken[] tokens, Map<String, Object> values)324 public static void setValues(LabelToken[] tokens, Map<String, Object> values) { 325 for (int i = 0; i < tokens.length; i++) { 326 LabelToken lt = tokens[i]; 327 if (lt == null) 328 break; 329 if (lt.key == null) 330 continue; 331 Object value = values.get(lt.key); 332 lt.text = (value instanceof Float ? lt.format(((Float) value) 333 .floatValue(), null, null) : lt.format(Float.NaN, (String) value, 334 null)); 335 } 336 } 337 getLabel(LabelToken[] tokens)338 public static String getLabel(LabelToken[] tokens) { 339 SB sb = new SB(); 340 for (int i = 0; i < tokens.length; i++) { 341 LabelToken lt = tokens[i]; 342 if (lt == null) 343 break; 344 sb.append(lt.text); 345 } 346 return sb.toString(); 347 } 348 349 /////////////////// private methods 350 351 /** 352 * sets a label token based on a label string 353 * 354 * @param vwr 355 * @param strFormat 356 * @param lt 357 * @param cch 358 * @param chAtom 359 * @param htValues 360 * @return new position 361 */ setToken(Viewer vwr, String strFormat, LabelToken lt, int cch, int chAtom, Map<String, Object> htValues)362 private static int setToken(Viewer vwr, String strFormat, LabelToken lt, 363 int cch, int chAtom, Map<String, Object> htValues) { 364 int ich = lt.pt + 1; 365 // trailing % is OK 366 if (ich >= cch) { 367 lt.text = "%"; 368 return ich; 369 } 370 char ch; 371 if (strFormat.charAt(ich) == '-') { 372 lt.alignLeft = true; 373 ++ich; 374 } 375 if (ich < cch && strFormat.charAt(ich) == '0') { 376 lt.zeroPad = true; 377 ++ich; 378 } 379 while (ich < cch && PT.isDigit(ch = strFormat.charAt(ich))) { 380 lt.width = (10 * lt.width) + (ch - '0'); 381 ++ich; 382 } 383 lt.precision = Integer.MAX_VALUE; 384 boolean isNegative = false; 385 if (ich < cch && strFormat.charAt(ich) == '.') { 386 ++ich; 387 if (ich < cch && (ch = strFormat.charAt(ich)) == '-') { 388 isNegative = true; 389 ++ich; 390 } 391 if (ich < cch && PT.isDigit(ch = strFormat.charAt(ich))) { 392 lt.precision = ch - '0'; 393 if (isNegative) 394 lt.precision = -1 - lt.precision; 395 ++ich; 396 } 397 } 398 if (ich < cch && htValues != null) 399 for (String key: htValues.keySet()) 400 if (strFormat.indexOf(key) == ich) 401 return ich + (lt.key = key).length(); 402 if (ich < cch) 403 switch (ch = strFormat.charAt(ich++)) { 404 case '%': 405 lt.text = "%"; 406 return ich; 407 case '[': 408 int ichClose = strFormat.indexOf(']', ich); 409 if (ichClose < ich) { 410 ich = cch; 411 break; 412 } 413 String propertyName = strFormat.substring(ich, ichClose).toLowerCase(); 414 if (propertyName.startsWith("property_")) { 415 lt.tok = T.data; 416 lt.data = vwr.getDataObj(propertyName, null, JmolDataManager.DATA_TYPE_AF); 417 } else if (propertyName.startsWith("validation.")) { 418 lt.tok = T.validation; 419 lt.data = vwr.getDataObj("property_" + propertyName.substring(11), null, JmolDataManager.DATA_TYPE_AF); 420 } else if (propertyName.startsWith("unitid")) { 421 lt.tok = T.id; 422 lt.data = Integer.valueOf(JC.getUnitIDFlags(propertyName.substring(6))); 423 } else { 424 T token = T.getTokenFromName(propertyName); 425 if (token != null && isLabelPropertyTok(token.tok)) 426 lt.tok = token.tok; 427 } 428 ich = ichClose + 1; 429 break; 430 case '{': 431 // label %{altName} 432 // client property name deprecated in 12.1.22 433 // but this can be passed to Jmol from the reader 434 // as an auxiliaryInfo array or '\n'-delimited string 435 int ichCloseBracket = strFormat.indexOf('}', ich); 436 if (ichCloseBracket < ich) { 437 ich = cch; 438 break; 439 } 440 String s = strFormat.substring(ich, ichCloseBracket); 441 lt.data = vwr.getDataObj(s, null, JmolDataManager.DATA_TYPE_AF); 442 // TODO untested j2s issue fix 443 if (lt.data == null) { 444 lt.data = vwr.getDataObj(s, null, JmolDataManager.DATA_TYPE_UNKNOWN); 445 if (lt.data != null) { 446 lt.data = ((Object[]) lt.data)[1]; 447 if (lt.data instanceof String) 448 lt.data = PT.split((String) lt.data, "\n"); 449 if (!(AU.isAS(lt.data))) 450 lt.data = null; 451 } 452 if (lt.data == null) { 453 lt.tok = T.property; 454 lt.data = s; 455 } else { 456 lt.tok = T.array; 457 } 458 } else { 459 lt.tok = T.data; 460 } 461 ich = ichCloseBracket + 1; 462 break; 463 default: 464 int i, 465 i1; 466 if (ich < cch && (i = twoCharLabelTokenParams.indexOf(ch)) >= 0 467 && (i1 = "xyz".indexOf(strFormat.charAt(ich))) >= 0) { 468 lt.tok = twoCharLabelTokenIds[i * 3 + i1]; 469 ich++; 470 } else if ((i = labelTokenParams.indexOf(ch)) >= 0) { 471 lt.tok = labelTokenIds[i]; 472 } 473 } 474 lt.text = strFormat.substring(lt.pt, ich); 475 if (ich < cch && chAtom != '\0' 476 && PT.isDigit(ch = strFormat.charAt(ich))) { 477 ich++; 478 lt.ch1 = ch; 479 if (ch != chAtom && chAtom != '\1') 480 lt.tok = 0; 481 } 482 return ich; 483 } 484 appendAtomTokenValue(Viewer vwr, Atom atom, LabelToken t, SB strLabel, int[] indices, P3 ptTemp)485 private static void appendAtomTokenValue(Viewer vwr, Atom atom, LabelToken t, 486 SB strLabel, int[] indices, P3 ptTemp) { 487 String strT = null; 488 float floatT = Float.NaN; 489 T3 ptT = null; 490 try { 491 switch (t.tok) { 492 493 // special cases only for labels 494 495 case T.atomindex: 496 strT = "" + (indices == null ? atom.i : indices[atom.i]); 497 break; 498 case T.color: 499 ptT = atom.atomPropertyTuple(vwr, t.tok, ptTemp); 500 break; 501 case T.id: 502 strT = atom.getUnitID(((Integer) t.data).intValue()); 503 break; 504 case T.data: 505 case T.validation: 506 if (t.data != null) { 507 floatT = ((float[]) t.data)[atom.i]; 508 if (t.tok == T.validation && floatT != 1 && floatT != 0) { 509 Lst<Float> o = vwr.getAtomValidation( 510 t.text.substring(13, t.text.length() - 1), atom); 511 if (o == null) { 512 System.out.println("?? o is null ??"); 513 } else if (o.size() == 1) { 514 floatT = o.get(0).floatValue(); 515 } else { 516 floatT = Float.NaN; 517 strT = ""; 518 for (int i = 0, n = o.size(); i < n; i++) { 519 strT += "," + o.get(i); 520 } 521 if (strT.length() > 1) 522 strT = strT.substring(1); 523 } 524 } 525 } 526 break; 527 case T.property: 528 // label %{altName} 529 Object data = vwr.ms.getInfo(atom.mi, (String) t.data); 530 int iatom = atom.i - vwr.ms.am[atom.mi].firstAtomIndex; 531 Object o = null; 532 if (iatom >= 0) 533 if ((data instanceof Object[])) { 534 // unlikely that this will be the case. 535 // it would have to be 536 Object[] sdata = (Object[]) data; 537 o = (iatom < sdata.length ? sdata[iatom] : null); 538 } else if (data instanceof Lst<?>) { 539 @SuppressWarnings("unchecked") 540 Lst<SV> list = (Lst<SV>) data; 541 o = (iatom < list.size() ? SV.oValue(list.get(iatom)) : null); 542 } 543 if (o == null) { 544 strT = ""; 545 } else if (o instanceof Float) { 546 floatT = ((Float) o).floatValue(); 547 } else if (o instanceof Integer) { 548 floatT = ((Integer) o).intValue(); 549 } else if (o instanceof T3) { 550 ptT = (T3) o; 551 } else { 552 strT = o.toString(); 553 } 554 break; 555 case T.array: 556 if (t.data != null) { 557 String[] sdata = (String[]) t.data; 558 strT = (atom.i < sdata.length ? sdata[atom.i] : ""); 559 } 560 break; 561 case T.formalcharge: 562 int formalCharge = atom.getFormalCharge(); 563 strT = (formalCharge > 0 ? "" + formalCharge + "+" 564 : formalCharge < 0 ? "" + -formalCharge + "-" : ""); 565 break; 566 case T.model: 567 strT = atom.getModelNumberForLabel(); 568 break; 569 case T.occupancy: 570 strT = "" + atom.atomPropertyInt(t.tok); 571 break; 572 case T.radius: 573 floatT = atom.atomPropertyFloat(vwr, t.tok, ptTemp); 574 break; 575 case T.strucid: 576 strT = atom.group.getStructureId(); 577 break; 578 case T.strucno: 579 int id = atom.group.getStrucNo(); 580 strT = (id <= 0 ? "" : "" + id); 581 break; 582 case T.straightness: 583 if (Float.isNaN(floatT = atom.group.getGroupParameter(T.straightness))) 584 strT = "null"; 585 break; 586 case T.vibx: 587 case T.viby: 588 case T.vibz: 589 case T.modx: 590 case T.mody: 591 case T.modz: 592 case T.modo: 593 floatT = atom.atomPropertyFloat(vwr, t.tok, ptTemp); 594 if (Float.isNaN(floatT)) 595 strT = ""; 596 break; 597 case T.nbo: 598 strT = vwr.getNBOAtomLabel(atom); 599 break; 600 case T.seqcode: // see 1h4w 184^A 601 case T.structure: 602 case T.substructure: 603 strT = atom.atomPropertyString(vwr, t.tok); 604 break; 605 case T.w: 606 strT = atom.getIdentityXYZ(false, ptTemp); 607 break; 608 609 // characters only 610 // JavaScript switch cannot handle mixed cases of numbers and character codes 611 case 79://'O': 612 strT = atom.getSymmetryOperatorList(false); 613 break; 614 case 81://'Q': 615 floatT = atom.getOccupancy100() / 100f; 616 break; 617 618 // standard 619 620 default: 621 switch (t.tok & T.PROPERTYFLAGS) { 622 case T.intproperty: 623 if (t.intAsFloat) 624 floatT = atom.atomPropertyInt(t.tok); 625 else 626 strT = "" + atom.atomPropertyInt(t.tok); 627 break; 628 case T.floatproperty: 629 floatT = atom.atomPropertyFloat(vwr, t.tok, ptTemp); 630 break; 631 case T.strproperty: 632 strT = atom.atomPropertyString(vwr, t.tok); 633 break; 634 case T.atomproperty: 635 ptT = atom.atomPropertyTuple(vwr, t.tok, ptTemp); 636 if (ptT == null) 637 strT = ""; 638 break; 639 default: 640 // any dual case would be here -- must handle specially 641 } 642 } 643 } catch (IndexOutOfBoundsException ioobe) { 644 floatT = Float.NaN; 645 strT = null; 646 ptT = null; 647 } 648 strT = t.format(floatT, strT, ptT); 649 if (strLabel == null) 650 t.text = strT; 651 else 652 strLabel.append(strT); 653 } 654 format(float floatT, String strT, T3 ptT)655 private String format(float floatT, String strT, T3 ptT) { 656 if (!Float.isNaN(floatT)) { 657 return PT.formatF(floatT, width, precision, alignLeft, zeroPad); 658 } else if (strT != null) { 659 return PT.formatS(strT, width, precision, alignLeft, zeroPad); 660 } else if (ptT != null) { 661 if (width == 0 && precision == Integer.MAX_VALUE) { 662 width = 6; 663 precision = 2; 664 } 665 return PT.formatF(ptT.x, width, precision, false, false) 666 + PT.formatF(ptT.y, width, precision, false, false) 667 + PT.formatF(ptT.z, width, precision, false, false); 668 } else { 669 return text; 670 } 671 } 672 673 } 674