1 /* Copyright (c) 2002-2012 The University of the West Indies 2 * 3 * Contact: robert.lancashire@uwimona.edu.jm 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 package jspecview.common; 21 22 import java.util.Hashtable; 23 import java.util.Map; 24 25 import javajs.api.GenericColor; 26 import javajs.util.Lst; 27 import javajs.util.PT; 28 29 30 import org.jmol.util.Logger; 31 32 import jspecview.source.JDXDataObject; 33 import jspecview.source.JDXSourceStreamTokenizer; 34 35 /** 36 * <code>JDXSpectrum</code> implements the Interface Spectrum for the display of 37 * JDX Files. 38 * 39 * @author Bob Hanson 40 * @author Debbie-Ann Facey 41 * @author Khari A. Bryan 42 * @author Prof Robert J. Lancashire 43 */ 44 public class Spectrum extends JDXDataObject { 45 46 public String id = ""; 47 48 GenericColor fillColor; 49 50 /** 51 * spectra that can never be displayed independently, or at least not by 52 * default; 2D slices, for example 53 */ 54 private Lst<Spectrum> subSpectra; 55 private Lst<PeakInfo> peakList = new Lst<PeakInfo>(); 56 private String peakXLabel, peakYLabel; 57 private PeakInfo selectedPeak, highlightedPeak; 58 private Spectrum convertedSpectrum; 59 60 private double specShift = 0; 61 private double userYFactor = 1; 62 63 private int currentSubSpectrumIndex; 64 65 private boolean isForcedSubset; 66 private boolean exportXAxisLeftToRight; 67 68 69 70 71 public enum IRMode { 72 NO_CONVERT, TO_TRANS, TO_ABS, TOGGLE; getMode(String value)73 public static IRMode getMode(String value) { 74 switch (value == null ? 'I' : value.toUpperCase().charAt(0)) { 75 case 'A': 76 return TO_ABS; 77 case 'T': 78 return (value.equalsIgnoreCase("TOGGLE") ? TOGGLE : TO_TRANS); 79 case 'N': 80 return NO_CONVERT; 81 default: 82 return TOGGLE; 83 } 84 } 85 } 86 dispose()87 public void dispose() { 88 // NO! NEVER DO THIS!!! 89 // Just because a spectrum is no longer needed by a graphSet does not mean it 90 // is gone. 91 // if (subSpectra != null) 92 // for (int i = 0; i < subSpectra.size(); i++) 93 // if (subSpectra.get(i) != this) 94 // subSpectra.get(i).dispose(); 95 // subSpectra = null; 96 // parent = null; 97 // peakList = null; 98 // selectedPeak = null; 99 } 100 isForcedSubset()101 public boolean isForcedSubset() { 102 return isForcedSubset; 103 } 104 setId(String id)105 public void setId(String id) { 106 this.id = id; 107 } 108 109 /** 110 * Constructor 111 */ Spectrum()112 public Spectrum() { 113 //System.out.println("initialize JDXSpectrum " + this); 114 headerTable = new Lst<String[]>(); 115 xyCoords = new Coordinate[0]; 116 parent = this; 117 } 118 119 /** 120 * specifically for Abs/Trans conversion. Note that we do NOT carry over piUnitsY 121 * 122 * @return a copy of this <code>JDXSpectrum</code> 123 */ copy()124 public Spectrum copy() { 125 Spectrum newSpectrum = new Spectrum(); 126 copyTo(newSpectrum); 127 newSpectrum.setPeakList(peakList, peakXLabel, null); 128 newSpectrum.fillColor = fillColor; 129 return newSpectrum; 130 } 131 132 /** 133 * Returns the array of coordinates 134 * 135 * @return the array of coordinates 136 */ getXYCoords()137 public Coordinate[] getXYCoords() { 138 return getCurrentSubSpectrum().xyCoords; 139 } 140 141 getPeakList()142 public Lst<PeakInfo> getPeakList() { 143 return peakList; 144 } 145 setPeakList(Lst<PeakInfo> list, String peakXLabel, String peakYLabel)146 public int setPeakList(Lst<PeakInfo> list, String peakXLabel, String peakYLabel) { 147 peakList = list; 148 this.peakXLabel = peakXLabel; 149 this.peakYLabel = peakYLabel; 150 for (int i = list.size(); --i >= 0; ) 151 peakList.get(i).spectrum = this; 152 if (Logger.debugging) 153 Logger.info("Spectrum " + getTitle() + " peaks: " + list.size()); 154 return list.size(); 155 } 156 selectPeakByFileIndex(String filePath, String index, String atomKey)157 public PeakInfo selectPeakByFileIndex(String filePath, String index, 158 String atomKey) { 159 if (peakList != null && peakList.size() > 0 160 && (atomKey == null || sourceID.equals(index))) 161 for (int i = 0; i < peakList.size(); i++) 162 if (peakList.get(i).checkFileIndex(filePath, index, atomKey)) { 163 System.out.println("selecting peak by FileIndex " + this + " " 164 + peakList.get(i)); 165 return (selectedPeak = peakList.get(i)); 166 } 167 return null; 168 } 169 selectPeakByFilePathTypeModel(String filePath, String type, String model)170 public PeakInfo selectPeakByFilePathTypeModel(String filePath, String type, String model) { 171 if (peakList != null && peakList.size() > 0) 172 for (int i = 0; i < peakList.size(); i++) 173 if (peakList.get(i).checkFileTypeModel(filePath, type, model)) { 174 System.out.println("selecting peak byFilePathTypeModel " + this + " " + peakList.get(i)); 175 return (selectedPeak = peakList.get(i)); 176 } 177 return null; 178 } 179 180 /** 181 * Find a matching spectrum by type (IR, 1HNMR,...) and model name 182 * 183 * @param type if null, then model is a sourceID to match 184 * @param model 185 * @return true for match 186 */ matchesPeakTypeModel(String type, String model)187 public boolean matchesPeakTypeModel(String type, String model) { 188 if (type.equals("ID")) 189 return (sourceID.equalsIgnoreCase(model)); 190 if (peakList != null && peakList.size() > 0) 191 for (int i = 0; i < peakList.size(); i++) 192 if (peakList.get(i).checkTypeModel(type, model)) 193 return true; 194 return false; 195 } 196 197 setSelectedPeak(PeakInfo peak)198 public void setSelectedPeak(PeakInfo peak) { 199 selectedPeak = peak; 200 } 201 setHighlightedPeak(PeakInfo peak)202 public void setHighlightedPeak(PeakInfo peak) { 203 highlightedPeak = peak; 204 } 205 getSelectedPeak()206 public PeakInfo getSelectedPeak() { 207 return selectedPeak; 208 } 209 getModelPeakInfoForAutoSelectOnLoad()210 public PeakInfo getModelPeakInfoForAutoSelectOnLoad() { 211 if (peakList != null) 212 for (int i = 0; i < peakList.size(); i++) 213 if (peakList.get(i).autoSelectOnLoad()) 214 return peakList.get(i); 215 return null; 216 } 217 218 getAssociatedPeakInfo(int xPixel, Coordinate coord)219 public PeakInfo getAssociatedPeakInfo(int xPixel, Coordinate coord) { 220 selectedPeak = findPeakByCoord(xPixel, coord); 221 return (selectedPeak == null ? getBasePeakInfo() : selectedPeak); 222 } 223 findPeakByCoord(int xPixel, Coordinate coord)224 public PeakInfo findPeakByCoord(int xPixel, Coordinate coord) { 225 if (coord != null && peakList != null && peakList.size() > 0) { 226 double xVal = coord.getXVal(); 227 int iBest = -1; 228 double dBest = 1e100; 229 for (int i = 0; i < peakList.size(); i++) { 230 double d = peakList.get(i).checkRange(xPixel, xVal); 231 if (d < dBest) { 232 dBest = d; 233 iBest = i; 234 } 235 } 236 if (iBest >= 0) 237 return peakList.get(iBest); 238 } 239 return null; 240 } 241 getPeakTitle()242 public String getPeakTitle() { 243 return (selectedPeak != null ? selectedPeak.getTitle() : highlightedPeak != null ? highlightedPeak.getTitle() : getTitleLabel()); 244 } 245 246 private String titleLabel; 247 getTitleLabel()248 public String getTitleLabel() { 249 if (titleLabel != null) 250 return titleLabel; 251 String type = (peakList == null || peakList.size() == 0 ? 252 getQualifiedDataType() : 253 peakList.get(0).getType()); 254 if (type != null && type.startsWith("NMR")) { 255 if (nucleusY != null && !nucleusY.equals("?")) { 256 type = "2D" + type; 257 } else { 258 type = getNominalSpecFreq(nucleusX, getObservedFreq()) + " MHz " + nucleusX + " " + type; 259 } 260 } 261 return titleLabel = (type != null && type.length() > 0 ? type + " " : "") 262 + getTitle(); 263 } 264 setNextPeak(Coordinate coord, int istep)265 public int setNextPeak(Coordinate coord, int istep) { 266 if (peakList == null || peakList.size() == 0) 267 return -1; 268 double x0 = coord.getXVal() + istep * 0.000001; 269 int ipt1 = -1; 270 int ipt2 = -1; 271 double dmin1 = Double.MAX_VALUE * istep; 272 double dmin2 = 0; 273 for (int i = peakList.size(); --i >= 0;) { 274 double x = peakList.get(i).getX(); 275 if (istep > 0) { 276 if (x > x0 && x < dmin1) { 277 // nearest on right 278 ipt1 = i; 279 dmin1 = x; 280 } else if (x < x0 && x - x0 < dmin2) { 281 // farthest on left 282 ipt2 = i; 283 dmin2 = x - x0; 284 } 285 } else { 286 if (x < x0 && x > dmin1) { 287 // nearest on left 288 ipt1 = i; 289 dmin1 = x; 290 } else if (x > x0 && x - x0 > dmin2) { 291 // farthest on right 292 ipt2 = i; 293 dmin2 = x - x0; 294 } 295 } 296 } 297 298 if (ipt1 < 0) { 299 if (ipt2 < 0) 300 return -1; 301 ipt1 = ipt2; 302 } 303 return ipt1; 304 } 305 getPercentYValueAt(double x)306 public double getPercentYValueAt(double x) { 307 if (!isContinuous()) 308 return Double.NaN; 309 return getYValueAt(x); 310 } 311 getYValueAt(double x)312 public double getYValueAt(double x) { 313 return Coordinate.getYValueAt(xyCoords, x); 314 } 315 316 317 /** 318 * Set by JSViewer 319 * 320 * @param userYFactor 321 */ setUserYFactor(double userYFactor)322 public void setUserYFactor(double userYFactor) { 323 this.userYFactor = userYFactor; 324 } 325 getUserYFactor()326 public double getUserYFactor() { 327 return userYFactor; 328 } 329 330 public static final double MAXABS = 4; // maximum absorbance allowed 331 getConvertedSpectrum()332 public Spectrum getConvertedSpectrum() { 333 return convertedSpectrum; 334 } 335 setConvertedSpectrum(Spectrum spectrum)336 public void setConvertedSpectrum(Spectrum spectrum) { 337 convertedSpectrum = spectrum; 338 } 339 taConvert(Spectrum spectrum, IRMode mode)340 public static Spectrum taConvert(Spectrum spectrum, IRMode mode) { 341 if (!spectrum.isContinuous()) 342 return spectrum; 343 switch (mode) { 344 case NO_CONVERT: 345 return spectrum; 346 case TO_ABS: 347 if (!spectrum.isTransmittance()) 348 return spectrum; 349 break; 350 case TO_TRANS: 351 if (!spectrum.isAbsorbance()) 352 return spectrum; 353 break; 354 case TOGGLE: 355 break; 356 } 357 Spectrum spec = spectrum.getConvertedSpectrum(); 358 return (spec != null ? spec : spectrum.isAbsorbance() ? toT(spectrum) : toA(spectrum)); 359 } 360 361 /** 362 * Converts a spectrum from Absorbance to Transmittance 363 * 364 * @param spectrum 365 * the JDXSpectrum 366 * @return the converted spectrum 367 */ 368 toT(Spectrum spectrum)369 private static Spectrum toT(Spectrum spectrum) { 370 if (!spectrum.isAbsorbance()) 371 return null; 372 Coordinate[] xyCoords = spectrum.getXYCoords(); 373 Coordinate[] newXYCoords = new Coordinate[xyCoords.length]; 374 if (!Coordinate.isYInRange(xyCoords, 0, MAXABS)) 375 xyCoords = Coordinate.normalise(xyCoords, 0, MAXABS); 376 for (int i = 0; i < xyCoords.length; i++) 377 newXYCoords[i] = new Coordinate().set(xyCoords[i].getXVal(), 378 toTransmittance(xyCoords[i].getYVal())); 379 return newSpectrum(spectrum, newXYCoords, "TRANSMITTANCE"); 380 } 381 382 /** 383 * Converts a spectrum from Transmittance to Absorbance 384 * 385 * @param spectrum 386 * the JDXSpectrum 387 * @return the converted spectrum 388 */ toA(Spectrum spectrum)389 private static Spectrum toA(Spectrum spectrum) { 390 if (!spectrum.isTransmittance()) 391 return null; 392 Coordinate[] xyCoords = spectrum.getXYCoords(); 393 Coordinate[] newXYCoords = new Coordinate[xyCoords.length]; 394 boolean isPercent = Coordinate.isYInRange(xyCoords, -2, 2); 395 for (int i = 0; i < xyCoords.length; i++) 396 newXYCoords[i] = new Coordinate().set(xyCoords[i].getXVal(), 397 toAbsorbance(xyCoords[i].getYVal(), isPercent)); 398 return newSpectrum(spectrum, newXYCoords, "ABSORBANCE"); 399 } 400 401 /** 402 * copy spectrum with new coordinates 403 * 404 * @param spectrum 405 * @param newXYCoords 406 * @param units 407 * @return new spectrum 408 */ newSpectrum(Spectrum spectrum, Coordinate[] newXYCoords, String units)409 public static Spectrum newSpectrum(Spectrum spectrum, 410 Coordinate[] newXYCoords, 411 String units) { 412 Spectrum specNew = spectrum.copy(); 413 specNew.setOrigin("JSpecView Converted"); 414 specNew.setOwner("JSpecView Generated"); 415 specNew.setXYCoords(newXYCoords); 416 specNew.setYUnits(units); 417 spectrum.setConvertedSpectrum(specNew); 418 specNew.setConvertedSpectrum(spectrum); 419 return specNew; 420 } 421 422 /** 423 * Converts a value in Transmittance to Absorbance -- max of MAXABS (4) 424 * 425 * 426 * @param x 427 * @param isPercent 428 * @return the value in Absorbance 429 */ toAbsorbance(double x, boolean isPercent)430 private static double toAbsorbance(double x, boolean isPercent) { 431 return (Math.min(MAXABS, isPercent ? 2 - log10(x) : -log10(x))); 432 } 433 434 /** 435 * Converts a value from Absorbance to Transmittance 436 * 437 * @param x 438 * @return the value in Transmittance 439 */ toTransmittance(double x)440 private static double toTransmittance(double x) { 441 return (x <= 0 ? 1 : Math.pow(10, -x)); 442 } 443 444 /** 445 * Returns the log of a value to the base 10 446 * 447 * @param value 448 * the input value 449 * @return the log of a value to the base 10 450 */ log10(double value)451 private static double log10(double value) { 452 return Math.log(value) / Math.log(10); 453 } 454 process(Lst<Spectrum> specs, IRMode irMode)455 public static boolean process(Lst<Spectrum> specs, IRMode irMode) { 456 if (irMode == IRMode.TO_ABS || irMode == IRMode.TO_TRANS) 457 for (int i = 0; i < specs.size(); i++) 458 specs.set(i, taConvert(specs.get(i), irMode)); 459 return true; 460 } 461 getSubSpectra()462 public Lst<Spectrum> getSubSpectra() { 463 return subSpectra; 464 } 465 getCurrentSubSpectrum()466 public Spectrum getCurrentSubSpectrum() { 467 return (subSpectra == null ? this : subSpectra.get(currentSubSpectrumIndex)); 468 } 469 advanceSubSpectrum(int dir)470 public int advanceSubSpectrum(int dir) { 471 return setCurrentSubSpectrum(currentSubSpectrumIndex + dir); 472 } 473 setCurrentSubSpectrum(int n)474 public int setCurrentSubSpectrum(int n) { 475 return (currentSubSpectrumIndex = Coordinate.intoRange(n, 0, subSpectra.size() - 1)); 476 } 477 478 /** 479 * adds an nD subspectrum and titles it "Subspectrum <n>" 480 * These spectra can be iterated over using the UP and DOWN keys. 481 * 482 * @param spectrum 483 * @param forceSub 484 * @return true if was possible 485 */ addSubSpectrum(Spectrum spectrum, boolean forceSub)486 public boolean addSubSpectrum(Spectrum spectrum, boolean forceSub) { 487 if (!forceSub && (is1D() || blockID != spectrum.blockID) 488 || !allowSubSpec(this, spectrum)) 489 return false; 490 isForcedSubset = forceSub; // too many blocks (>100) 491 if (subSpectra == null) { 492 subSpectra = new Lst<Spectrum>(); 493 addSubSpectrum(this, true); 494 } 495 subSpectra.addLast(spectrum); 496 spectrum.parent = this; 497 //System.out.println("Added subspectrum " + subSpectra.size() + ": " + spectrum.y2D); 498 return true; 499 } 500 getSubIndex()501 public int getSubIndex() { 502 return (subSpectra == null ? -1 : currentSubSpectrumIndex); 503 } 504 setExportXAxisDirection(boolean leftToRight)505 public void setExportXAxisDirection(boolean leftToRight) { 506 exportXAxisLeftToRight = leftToRight; 507 } isExportXAxisLeftToRight()508 public boolean isExportXAxisLeftToRight() { 509 return exportXAxisLeftToRight; 510 } 511 getInfo(String key)512 public Map<String, Object> getInfo(String key) { 513 Map<String, Object> info = new Hashtable<String, Object>(); 514 if ("id".equalsIgnoreCase(key)) { 515 info.put(key, id); 516 return info; 517 } 518 String keys = null; 519 if ("".equals(key)) { 520 keys = "id specShift header"; 521 } 522 info.put("id", id); 523 Parameters.putInfo(key, info, "specShift", Double.valueOf(specShift)); 524 boolean justHeader = ("header".equals(key)); 525 if (!justHeader && key != null && keys == null) { 526 for (int i = headerTable.size(); --i >= 0;) { 527 String[] entry = headerTable.get(i); 528 if (entry[0].equalsIgnoreCase(key) || entry[2].equalsIgnoreCase(key)) { 529 info.put(key, entry[1]); 530 return info; 531 } 532 } 533 } 534 Map<String, Object> head = new Hashtable<String, Object>(); 535 String[][] list = getHeaderRowDataAsArray(); 536 for (int i = 0; i < list.length; i++) { 537 String label = JDXSourceStreamTokenizer.cleanLabel(list[i][0]); 538 if (keys != null) { 539 keys += " " + label; 540 continue; 541 } 542 if (key != null && !justHeader && !label.equals(key)) 543 continue; 544 Object val = fixInfoValue(list[i][1]); 545 if (key == null) { 546 Map<String, Object> data = new Hashtable<String, Object>(); 547 data.put("value", val); 548 data.put("index", Integer.valueOf(i + 1)); 549 info.put(label, data); 550 } else { 551 info.put(label, val); 552 } 553 } 554 if (head.size() > 0) 555 info.put("header", head); 556 if (!justHeader) { 557 if (keys != null) { 558 keys += " titleLabel type isHZToPPM subSpectrumCount"; 559 } 560 else { 561 562 Parameters.putInfo(key, info, "titleLabel", getTitleLabel()); 563 Parameters.putInfo(key, info, "type", getDataType()); 564 Parameters.putInfo(key, info, "isHZToPPM", Boolean.valueOf(isHZtoPPM())); 565 Parameters.putInfo(key, info, "subSpectrumCount", Integer 566 .valueOf(subSpectra == null ? 0 : subSpectra.size())); 567 } 568 } 569 if (keys != null) 570 info.put("KEYS", keys); 571 return info; 572 } 573 fixInfoValue(String info)574 private static Object fixInfoValue(String info) { 575 try { return (Integer.valueOf(info)); } catch (Exception e) {} 576 try { return (Double.valueOf(info)); } catch (Exception e) {} 577 return info; 578 } 579 findMatchingPeakInfo(PeakInfo pi)580 public PeakInfo findMatchingPeakInfo(PeakInfo pi) { 581 for (int i = 0; i < peakList.size(); i++) 582 if (peakList.get(i).checkTypeMatch(pi)) 583 return peakList.get(i); 584 return null; 585 } 586 getBasePeakInfo()587 public PeakInfo getBasePeakInfo() { 588 return (peakList.size() == 0 ? new PeakInfo() : 589 new PeakInfo(" baseModel=\"\" " + peakList.get(0))); 590 } 591 592 /** 593 * checks in order: (1) Peaks tag attribute xUnits/yUnits, 594 * then (2) ##XLABEL/##YLABEL, 595 * then (3) ##XUNITS/##YUNITS 596 * @param isX 597 * @return suitable label or "" 598 */ getAxisLabel(boolean isX)599 public String getAxisLabel(boolean isX) { 600 String label = (isX ? peakXLabel : peakYLabel); 601 if (label == null) 602 label = (isX ? xLabel : yLabel); 603 if (label == null) 604 label = (isX ? xUnits : yUnits); 605 return (label == null ? "" 606 : label.equalsIgnoreCase("WAVENUMBERS") ? "1/cm" 607 : label.equalsIgnoreCase("nanometers") ? "nm" 608 : label); 609 } 610 findXForPeakNearest(double x)611 public double findXForPeakNearest(double x) { 612 return Coordinate.findXForPeakNearest(xyCoords, x, isInverted()); 613 } 614 addSpecShift(double dx)615 public double addSpecShift(double dx) { 616 if (dx != 0) { 617 specShift += dx; 618 Coordinate.shiftX(xyCoords, dx); 619 if (subSpectra != null) 620 for (int i = subSpectra.size(); --i >= 0;) { 621 Spectrum spec = subSpectra.get(i); 622 if (spec != this && spec != parent) 623 spec.addSpecShift(dx); 624 } 625 } 626 return specShift; 627 } 628 allowSubSpec(Spectrum s1, Spectrum s2)629 public static boolean allowSubSpec(Spectrum s1, Spectrum s2) { 630 return (s1.is1D() == s2.is1D() 631 && s1.xUnits.equalsIgnoreCase(s2.xUnits) 632 && s1.isHNMR() == s2.isHNMR()); 633 } 634 areXScalesCompatible(Spectrum s1, Spectrum s2, boolean isSubspecCheck, boolean isLinkCheck)635 public static boolean areXScalesCompatible(Spectrum s1, Spectrum s2, 636 boolean isSubspecCheck, boolean isLinkCheck) { 637 boolean isNMR1 = s1.isNMR(); 638 // must be both NMR or both not NMR, 639 // and both must be continuous (because of X scaling) 640 // and must have same xUnits if not a link check 641 if (isNMR1 != s2.isNMR() 642 || s1.isContinuous() != s2.isContinuous() 643 || !isLinkCheck && !areUnitsCompatible(s1.xUnits, s2.xUnits)) 644 return false; 645 if (isSubspecCheck) { 646 // must both be 1D (or both be 2D?) for adding subspectra 647 if (s1.is1D() != s2.is1D()) 648 return false; 649 } else if (isLinkCheck) { 650 if (!isNMR1) 651 return true; 652 // we allow 1D/2D here 653 } else if (!s1.is1D() || !s2.is1D()) { 654 // otherwise we don't want to consider any 2D spectra 655 return false; 656 } 657 // done if this is not NMR comparison 658 // or check same nuclei // for now not going 1D-->2D 659 return (!isNMR1 || s2.is1D() && s1.parent.nucleusX.equals(s2.parent.nucleusX)); 660 } 661 areUnitsCompatible(String u1, String u2)662 private static boolean areUnitsCompatible(String u1, String u2) { 663 if (u1.equalsIgnoreCase(u2)) 664 return true; 665 u1 = u1.toUpperCase(); 666 u2 = u2.toUpperCase(); 667 return (u1.equals("HZ") && u2.equals("PPM") 668 || u1.equals("PPM") && u2.equals("HZ")); 669 } 670 areLinkableX(Spectrum s1, Spectrum s2)671 public static boolean areLinkableX(Spectrum s1, Spectrum s2) { 672 return (s1.isNMR() && s2.isNMR() && s1.nucleusX.equals(s2.nucleusX)); 673 } 674 areLinkableY(Spectrum s1, Spectrum s2)675 public static boolean areLinkableY(Spectrum s1, Spectrum s2) { 676 return (s1.isNMR() && s2.isNMR() && s1.nucleusX.equals(s2.nucleusY)); 677 } 678 679 // analysis fields 680 getPeakWidth()681 public float getPeakWidth() { 682 double w = getLastX() - getFirstX(); 683 return (float) (w/100); 684 } 685 setSimulated(String filePath)686 public void setSimulated(String filePath) { 687 isSimulation = true; 688 String s = sourceID; 689 if (s.length() == 0) 690 s = PT.rep(filePath, JSVFileManager.SIMULATION_PROTOCOL, ""); 691 if (s.indexOf("MOL=") >= 0) 692 s = ""; 693 title = "SIMULATED " + PT.rep(s, "$", ""); 694 695 } 696 setFillColor(GenericColor color)697 public void setFillColor(GenericColor color) { 698 fillColor = color; 699 if (convertedSpectrum != null) 700 convertedSpectrum.fillColor = color; 701 } 702 703 @Override toString()704 public String toString() { 705 return getTitleLabel() + (xyCoords == null ? "" : " xyCoords.length=" + xyCoords.length); 706 } 707 708 709 }