1 /* $RCSfile$ 2 * $Author: egonw $ 3 * $Date: 2005-11-10 09:52:44 -0600 (Thu, 10 Nov 2005) $ 4 * $Revision: 4255 $ 5 * 6 * Copyright (C) 2002-2005 The Jmol Development Team 7 * 8 * Contact: jmol-developers@lists.sf.net 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 package org.jmol.modelset; 25 26 import javajs.util.P3; 27 import javajs.util.P3i; 28 import javajs.util.PT; 29 import javajs.util.SB; 30 import javajs.util.BS; 31 32 import org.jmol.shape.Shape; 33 import org.jmol.util.C; 34 import org.jmol.util.Font; 35 import org.jmol.util.Txt; 36 import org.jmol.viewer.JC; 37 import org.jmol.viewer.Viewer; 38 39 public class Text { 40 41 private Viewer vwr; 42 43 public boolean doFormatText; 44 45 public Font font; 46 private byte fid; 47 private int ascent; 48 public int descent; 49 private int lineHeight; 50 51 protected int offsetX; // Labels only 52 protected int offsetY; // Labels only 53 public int boxYoff2; 54 55 private int[] widths; 56 57 private int textWidth; 58 private int textHeight; 59 public String text; 60 public String textUnformatted; 61 public String[] lines; 62 63 public Object image; 64 public float imageScale = 1; 65 66 67 Text()68 public Text() { 69 // public for reflection 70 // requires .newLabel or .newEcho 71 boxXY = new float[5]; 72 } 73 newLabel(Viewer vwr, Font font, String text, short colix, short bgcolix, int align, float scalePixelsPerMicron)74 static public Text newLabel(Viewer vwr, Font font, String text, 75 short colix, short bgcolix, int align, float scalePixelsPerMicron) { 76 // for labels and hover 77 Text t = new Text(); 78 t.vwr = vwr; 79 t.set(font, colix, align, scalePixelsPerMicron); 80 t.setText(text); 81 t.bgcolix = bgcolix; 82 return t; 83 } 84 newMeasure(Viewer vwr, Font font, short colix)85 static public Text newMeasure(Viewer vwr, Font font, 86 short colix) { 87 Text t = new Text(); 88 t.vwr = vwr; 89 t.set(font, colix, 0, 0); 90 t.isMeasure = true; 91 return t; 92 } 93 newEcho(Viewer vwr, Font font, String target, short colix, int valign, int align, float scalePixelsPerMicron)94 public static Text newEcho(Viewer vwr, Font font, String target, 95 short colix, int valign, int align, 96 float scalePixelsPerMicron) { 97 Text t = new Text(); 98 t.isEcho = true; 99 t.vwr = vwr; 100 t.set(font, colix, align, scalePixelsPerMicron); 101 t.target = target; 102 t.valign = valign; 103 t.z = 2; 104 t.zSlab = Integer.MIN_VALUE; 105 return t; 106 } 107 set(Font font, short colix, int align, float scalePixelsPerMicron)108 private void set(Font font, short colix, int align, 109 float scalePixelsPerMicron) { 110 this.scalePixelsPerMicron = scalePixelsPerMicron; 111 this.isEcho = isEcho; 112 this.colix = colix; 113 this.align = align; 114 this.setFont(font, !isEcho); 115 } 116 setOffset(int offset)117 public void setOffset(int offset) { 118 //Labels only 119 offsetX = JC.getXOffset(offset); 120 offsetY = JC.getYOffset(offset); 121 pymolOffset = null; 122 valign = JC.ECHO_XY; 123 } 124 getFontMetrics()125 private void getFontMetrics() { 126 descent = font.getDescent(); 127 ascent = font.getAscent(); 128 lineHeight = ascent + descent; 129 } 130 setFontFromFid(byte fid)131 public void setFontFromFid(byte fid) { //labels only 132 if (this.fid == fid) 133 return; 134 fontScale = 0; 135 setFont(Font.getFont3D(fid), true); 136 } 137 setText(String text)138 public void setText(String text) { 139 if (image != null) 140 getFontMetrics(); 141 image = null; 142 if (text != null && text.length() == 0) 143 text = null; 144 if (this.text != null && this.text.equals(text)) 145 return; 146 this.text = textUnformatted = text; 147 doFormatText = (isEcho && text != null && (text.indexOf("%{") >= 0 || text 148 .indexOf("@{") >= 0)); 149 if (!doFormatText) 150 recalc(); 151 } 152 setImage(Object image)153 public void setImage(Object image) { 154 this.image = image; 155 // this.text will be file name 156 recalc(); 157 } 158 setScale(float scale)159 public void setScale(float scale) { 160 imageScale = scale; 161 recalc(); 162 } 163 setFont(Font f3d, boolean doAll)164 public void setFont(Font f3d, boolean doAll) { 165 font = f3d; 166 if (font == null) 167 return; 168 getFontMetrics(); 169 if (!doAll) 170 return; 171 fid = font.fid; 172 recalc(); 173 } 174 setFontScale(float scale)175 public void setFontScale(float scale) { 176 if (fontScale == scale) 177 return; 178 fontScale = scale; 179 if (fontScale != 0) 180 setFont(vwr.gdata.getFont3DScaled(font, scale), true); 181 } 182 recalc()183 private void recalc() { 184 if (image != null) { 185 textWidth = textHeight = 0; 186 boxWidth = vwr.apiPlatform.getImageWidth(image) * fontScale * imageScale; 187 boxHeight = vwr.apiPlatform.getImageHeight(image) * fontScale * imageScale; 188 ascent = 0; 189 return; 190 } 191 if (text == null) { 192 text = null; 193 lines = null; 194 widths = null; 195 return; 196 } 197 if (font == null) 198 return; 199 lines = PT.split(text, (text.indexOf("\n") >= 0 ? "\n" : "|")); 200 textWidth = 0; 201 widths = new int[lines.length]; 202 for (int i = lines.length; --i >= 0;) 203 textWidth = Math.max(textWidth, widths[i] = stringWidth(lines[i])); 204 textHeight = lines.length * lineHeight; 205 boxWidth = textWidth + (fontScale >= 2 ? 16 : 8); 206 boxHeight = textHeight + (fontScale >= 2 ? 16 : 8); 207 } 208 setPosition(float scalePixelsPerMicron, float imageFontScaling, boolean isAbsolute, float[] boxXY)209 public void setPosition(float scalePixelsPerMicron, float imageFontScaling, 210 boolean isAbsolute, float[] boxXY) { 211 if (boxXY == null) 212 boxXY = this.boxXY; 213 else 214 this.boxXY = boxXY; 215 setWindow(vwr.gdata.width, vwr.gdata.height, scalePixelsPerMicron); 216 if (scalePixelsPerMicron != 0 && this.scalePixelsPerMicron != 0) 217 setFontScale(scalePixelsPerMicron / this.scalePixelsPerMicron); 218 else if (fontScale != imageFontScaling) 219 setFontScale(imageFontScaling); 220 if (doFormatText) { 221 text = (isEcho ? Txt.formatText(vwr, textUnformatted) : textUnformatted); 222 recalc(); 223 } 224 float dx = offsetX * imageFontScaling; 225 float dy = offsetY * imageFontScaling; 226 xAdj = (fontScale >= 2 ? 8 : 4); 227 yAdj = ascent - lineHeight + xAdj; 228 if (!isEcho || pymolOffset != null) { 229 boxXY[0] = movableX; 230 boxXY[1] = movableY; 231 if (pymolOffset != null && pymolOffset[0] != 2 && pymolOffset[0] != 3) { 232 // [1,2,3] are in Angstroms, not screen pixels 233 float pixelsPerAngstrom = vwr.tm.scaleToScreen(z, 1000); 234 float pz = pymolOffset[3]; 235 float dz = (pz < 0 ? -1 : 1) * Math.max(pz == 0 ? 0.5f : 0, Math.abs(pz) - 1) 236 * pixelsPerAngstrom; 237 z -= (int) dz; 238 pixelsPerAngstrom = vwr.tm.scaleToScreen(z, 1000); 239 240 /* for whatever reason, Java returns an 241 * ascent that is considerably higher than a capital X 242 * forget leading! 243 * ______________________________________________ 244 * leading 245 * ________ 246 * X X 247 * X ascent 248 * __ X X _________ _________ 249 * _________ descent 250 * textHeight 251 * _________ 252 * X X lineHeight 253 * X ascent 254 * __ X X__________ _________ ___________ 255 * _________ descent 256 * 257 * 258 * 259 */ 260 // dx and dy are the overall object offset, with text 261 dx = getPymolXYOffset(pymolOffset[1], textWidth, pixelsPerAngstrom); 262 int dh = ascent - descent; 263 dy = -getPymolXYOffset(-pymolOffset[2], dh, pixelsPerAngstrom) 264 - (textHeight + dh) / 2; 265 266 //dy: added -lineHeight (for one line) 267 if (pymolOffset[0] == 1) { 268 // from PyMOL - back to original plan 269 dy -= descent; 270 } 271 272 // xAdj and yAdj are the adjustments for the box itself relative to the text 273 xAdj = (fontScale >= 2 ? 8 : 4); 274 yAdj = -descent; 275 boxXY[0] = movableX - xAdj; 276 boxXY[1] = movableY - yAdj; 277 isAbsolute = true; 278 boxYoff2 = -2; // empirical fudge factor 279 } else { 280 boxYoff2 = 0; 281 } 282 if (pymolOffset == null) 283 switch (align) { 284 case JC.TEXT_ALIGN_CENTER: 285 dy = 0; 286 dx = 0; 287 break; 288 case JC.TEXT_ALIGN_RIGHT: 289 boxXY[0] -= boxWidth; 290 //$FALL-THROUGH$ 291 case JC.TEXT_ALIGN_LEFT: 292 dy = 0; 293 } 294 //System.out.println(dx + " Text " + dy + " " + boxWidth + " " + boxHeight); 295 setBoxXY(boxWidth, boxHeight, dx, dy, boxXY, isAbsolute); 296 } else { 297 setPos(fontScale); 298 } 299 boxX = boxXY[0]; 300 boxY = boxXY[1]; 301 302 // adjust positions if necessary 303 304 if (adjustForWindow) 305 setBoxOffsetsInWindow(/*image == null ? fontScale * 5 :*/0, 306 isEcho ? 0 : 16 * fontScale + lineHeight, boxY - textHeight); 307 //if (!isAbsolute) 308 y0 = boxY + yAdj; 309 if (isMeasure && align != JC.TEXT_ALIGN_CENTER) 310 y0 += ascent + (lines.length - 1)/2f * lineHeight; 311 } 312 getPymolXYOffset(float off, int width, float ppa)313 private float getPymolXYOffset(float off, int width, float ppa) { 314 float f = (off < -1 ? -1 : off > 1 ? 0 : (off - 1) / 2); 315 // offset 316 // -3 -2 317 // -2 -1 318 // -1 0 absolute, -1 width 319 //-0.5 -3/4 width 320 // 0 -1/2 width 321 // 0.5 -1/4 width 322 // 1 0 323 // 2 1 324 // 3 2 325 off = (off < -1 || off > 1 ? off + (off < 0 ? 1 : -1) : 0); 326 return f * width + off * ppa; 327 } 328 setPos(float scale)329 private void setPos(float scale) { 330 float xLeft, xCenter, xRight; 331 boolean is3dEcho = (xyz != null); 332 if (valign == JC.ECHO_XY || valign == JC.ECHO_XYZ) { 333 float x = (movableXPercent != Integer.MAX_VALUE ? movableXPercent 334 * windowWidth / 100 : is3dEcho ? movableX : movableX * scale); 335 float offsetX = this.offsetX * scale; 336 xLeft = xRight = xCenter = x + offsetX; 337 } else { 338 xLeft = 5 * scale; 339 xCenter = windowWidth / 2; 340 xRight = windowWidth - xLeft; 341 } 342 343 // set box X from alignments 344 345 boxXY[0] = xLeft; 346 switch (align) { 347 case JC.TEXT_ALIGN_CENTER: 348 boxXY[0] = xCenter - boxWidth / 2; 349 break; 350 case JC.TEXT_ALIGN_RIGHT: 351 boxXY[0] = xRight - boxWidth; 352 } 353 354 // set box Y from alignments 355 356 boxXY[1] = 0; 357 switch (valign) { 358 case JC.ECHO_TOP: 359 break; 360 case JC.ECHO_MIDDLE: 361 boxXY[1] = windowHeight / 2; 362 break; 363 case JC.ECHO_BOTTOM: 364 boxXY[1] = windowHeight; 365 break; 366 default: 367 float y = (movableYPercent != Integer.MAX_VALUE ? movableYPercent 368 * windowHeight / 100 : is3dEcho ? movableY : movableY * scale); 369 boxXY[1] = (is3dEcho ? y : (windowHeight - y)) + offsetY * scale; 370 } 371 372 if (align == JC.TEXT_ALIGN_CENTER) 373 boxXY[1] -= (image != null ? boxHeight : xyz != null ? boxHeight 374 : ascent - boxHeight) / 2; 375 else if (image != null) 376 boxXY[1] -= 0; 377 else if (xyz != null) 378 boxXY[1] -= ascent / 2; 379 } 380 setBoxXY(float boxWidth, float boxHeight, float xOffset, float yOffset, float[] boxXY, boolean isAbsolute)381 public static void setBoxXY(float boxWidth, float boxHeight, float xOffset, 382 float yOffset, float[] boxXY, boolean isAbsolute) { 383 float xBoxOffset, yBoxOffset; 384 385 // these are based on a standard |_ grid, so y is reversed. 386 if (xOffset > 0 || isAbsolute) { 387 xBoxOffset = xOffset; 388 } else { 389 xBoxOffset = -boxWidth; 390 if (xOffset == 0) 391 xBoxOffset /= 2; 392 else 393 xBoxOffset += xOffset; 394 } 395 if (isAbsolute || yOffset > 0) { 396 yBoxOffset = -boxHeight - yOffset; 397 } else if (yOffset == 0) { 398 yBoxOffset = -boxHeight / 2; // - 2; removed in Jmol 11.7.45 06/24/2009 399 } else { 400 yBoxOffset = -yOffset; 401 } 402 boxXY[0] += xBoxOffset; 403 boxXY[1] += yBoxOffset; 404 boxXY[2] = boxWidth; 405 boxXY[3] = boxHeight; 406 } 407 stringWidth(String str)408 private int stringWidth(String str) { 409 int w = 0; 410 int f = 1; 411 int subscale = 1; //could be something less than that 412 if (str == null) 413 return 0; 414 if (str.indexOf("<su") < 0 && str.indexOf("<color") < 0) 415 return font.stringWidth(str); 416 int len = str.length(); 417 String s; 418 for (int i = 0; i < len; i++) { 419 if (str.charAt(i) == '<') { 420 if (i + 8 <= len && 421 (str.substring(i, i + 7).equals("<color ") || str.substring(i, i + 8).equals("</color>"))) { 422 int i1 = str.indexOf(">", i); 423 if (i1 >= 0) { 424 i = i1; 425 continue; 426 } 427 } 428 if (i + 5 <= len 429 && ((s = str.substring(i, i + 5)).equals("<sub>") || s 430 .equals("<sup>"))) { 431 i += 4; 432 f = subscale; 433 continue; 434 } 435 if (i + 6 <= len 436 && ((s = str.substring(i, i + 6)).equals("</sub>") || s 437 .equals("</sup>"))) { 438 i += 5; 439 f = 1; 440 continue; 441 } 442 } 443 w += font.stringWidth(str.substring(i, i + 1)) * f; 444 } 445 return w; 446 } 447 448 private float xAdj, yAdj; 449 450 private float y0; 451 452 public P3 pointerPt; // for echo 453 setXYA(float[] xy, int i)454 public void setXYA(float[] xy, int i) { 455 if (i == 0) { 456 xy[2] = boxX; 457 switch (align) { 458 case JC.TEXT_ALIGN_CENTER: 459 xy[2] += boxWidth / 2; 460 break; 461 case JC.TEXT_ALIGN_RIGHT: 462 xy[2] += boxWidth - xAdj; 463 break; 464 default: 465 xy[2] += xAdj; 466 } 467 xy[0] = xy[2]; 468 xy[1] = y0; 469 } 470 switch (align) { 471 case JC.TEXT_ALIGN_CENTER: 472 xy[0] = xy[2] - widths[i] / 2; 473 break; 474 case JC.TEXT_ALIGN_RIGHT: 475 xy[0] = xy[2] - widths[i]; 476 } 477 xy[1] += lineHeight; 478 } 479 appendFontCmd(SB s)480 public void appendFontCmd(SB s) { 481 s.append(" " + Shape.getFontCommand("echo", font)); 482 if (scalePixelsPerMicron > 0) 483 s.append(" " + (10000f / scalePixelsPerMicron)); // Angstroms per pixel 484 } 485 486 public boolean isMeasure; 487 public boolean isEcho; 488 public P3 xyz; 489 public String target; 490 public String script; 491 public short colix; 492 public short bgcolix; 493 public int pointer; 494 public float fontScale; 495 496 public int align; 497 public int valign; 498 public int atomX, atomY, atomZ = Integer.MAX_VALUE; 499 public int movableX, movableY, movableZ; // Echo only 500 public int movableXPercent = Integer.MAX_VALUE; // Echo only 501 public int movableYPercent = Integer.MAX_VALUE; // Echo only 502 public int movableZPercent = Integer.MAX_VALUE; // Echo only 503 504 public int z = 1; // front plane 505 public int zSlab = Integer.MIN_VALUE; // z for slabbing purposes -- may be near an atom 506 507 // PyMOL-type offset 508 // [mode, screenoffsetx,y,z (applied after tranform), positionOffsetx,y,z (applied before transform)] 509 public float[] pymolOffset; 510 511 protected int windowWidth; 512 protected int windowHeight; 513 public boolean adjustForWindow; 514 public float boxWidth; 515 public float boxHeight; 516 public float boxX; 517 public float boxY; 518 519 public int modelIndex = -1; 520 public boolean visible = true; 521 public boolean hidden = false; 522 523 public float[] boxXY; 524 525 public float scalePixelsPerMicron; 526 setScalePixelsPerMicron(float scalePixelsPerMicron)527 public void setScalePixelsPerMicron(float scalePixelsPerMicron) { 528 fontScale = 0;//fontScale * this.scalePixelsPerMicron / scalePixelsPerMicron; 529 this.scalePixelsPerMicron = scalePixelsPerMicron; 530 } 531 setXYZ(P3 xyz, boolean doAdjust)532 public void setXYZ(P3 xyz, boolean doAdjust) { 533 this.xyz = xyz; 534 if (xyz == null) 535 this.zSlab = Integer.MIN_VALUE; 536 if (doAdjust) { 537 valign = (xyz == null ? JC.ECHO_XY : JC.ECHO_XYZ); 538 adjustForWindow = (xyz == null); 539 } 540 } 541 setTranslucent(float level, boolean isBackground)542 public void setTranslucent(float level, boolean isBackground) { 543 if (isBackground) { 544 if (bgcolix != 0) 545 bgcolix = C.getColixTranslucent3(bgcolix, !Float.isNaN(level), level); 546 } else { 547 colix = C.getColixTranslucent3(colix, !Float.isNaN(level), level); 548 } 549 } 550 setMovableX(int x)551 public void setMovableX(int x) { 552 valign = (valign == JC.ECHO_XYZ ? JC.ECHO_XYZ : JC.ECHO_XY); 553 movableX = x; 554 movableXPercent = Integer.MAX_VALUE; 555 } 556 setMovableY(int y)557 public void setMovableY(int y) { 558 valign = (valign == JC.ECHO_XYZ ? JC.ECHO_XYZ : JC.ECHO_XY); 559 movableY = y; 560 movableYPercent = Integer.MAX_VALUE; 561 } 562 563 // public void setMovableZ(int z) { 564 // if (valign != VALIGN_XYZ) 565 // valign = VALIGN_XY; 566 // movableZ = z; 567 // movableZPercent = Integer.MAX_VALUE; 568 // } 569 setMovableXPercent(int x)570 public void setMovableXPercent(int x) { 571 valign = (valign == JC.ECHO_XYZ ? JC.ECHO_XYZ : JC.ECHO_XY); 572 movableX = Integer.MAX_VALUE; 573 movableXPercent = x; 574 } 575 setMovableYPercent(int y)576 public void setMovableYPercent(int y) { 577 valign = (valign == JC.ECHO_XYZ ? JC.ECHO_XYZ : JC.ECHO_XY); 578 movableY = Integer.MAX_VALUE; 579 movableYPercent = y; 580 } 581 setMovableZPercent(int z)582 public void setMovableZPercent(int z) { 583 if (valign != JC.ECHO_XYZ) 584 valign = JC.ECHO_XY; 585 movableZ = Integer.MAX_VALUE; 586 movableZPercent = z; 587 } 588 setZs(int z, int zSlab)589 public void setZs(int z, int zSlab) { 590 this.z = z; 591 this.zSlab = zSlab; 592 } 593 setXYZs(int x, int y, int z, int zSlab)594 public void setXYZs(int x, int y, int z, int zSlab) { 595 setMovableX(x); 596 setMovableY(y); 597 setZs(z, zSlab); 598 } 599 setScript(String script)600 public void setScript(String script) { 601 this.script = (script == null || script.length() == 0 ? null : script); 602 } 603 setAlignmentLCR(String align)604 public boolean setAlignmentLCR(String align) { 605 if ("left".equals(align)) 606 return setAlignment(JC.TEXT_ALIGN_LEFT); 607 if ("center".equals(align)) 608 return setAlignment(JC.TEXT_ALIGN_CENTER); 609 if ("right".equals(align)) 610 return setAlignment(JC.TEXT_ALIGN_RIGHT); 611 return false; 612 } 613 setAlignment(int align)614 public boolean setAlignment(int align) { 615 if (this.align != align) { 616 this.align = align; 617 recalc(); 618 } 619 return true; 620 } 621 setBoxOffsetsInWindow(float margin, float vMargin, float vTop)622 public void setBoxOffsetsInWindow(float margin, float vMargin, float vTop) { 623 // not labels 624 625 // these coordinates are (0,0) in top left 626 // (user coordinates are (0,0) in bottom left) 627 float bw = boxWidth + margin; 628 float x = boxX; 629 if (x + bw > windowWidth) 630 x = windowWidth - bw; 631 if (x < margin) 632 x = margin; 633 boxX = x; 634 635 float bh = boxHeight; 636 float y = vTop; 637 if (y + bh > windowHeight) 638 y = windowHeight - bh; 639 if (y < vMargin) 640 y = vMargin; 641 boxY = y; 642 } 643 setWindow(int width, int height, float scalePixelsPerMicron)644 public void setWindow(int width, int height, float scalePixelsPerMicron) { 645 windowWidth = width; 646 windowHeight = height; 647 if (pymolOffset == null && this.scalePixelsPerMicron < 0 648 && scalePixelsPerMicron != 0) 649 setScalePixelsPerMicron(scalePixelsPerMicron); 650 } 651 checkObjectClicked(boolean isAntialiased, int x, int y, BS bsVisible)652 public boolean checkObjectClicked(boolean isAntialiased, int x, int y, 653 BS bsVisible) { 654 if (hidden || script == null || modelIndex >= 0 && !bsVisible.get(modelIndex)) 655 return false; 656 if (isAntialiased) { 657 x <<= 1; 658 y <<= 1; 659 } 660 return (x >= boxX && x <= boxX + boxWidth && y >= boxY && y <= boxY 661 + boxHeight); 662 } 663 664 // 665 // new feature: set labelOffset [mode sx sy sz ax ay az] (3.1.15, never documented) 666 // new feature: PyMOL-like label offset options: 667 // 668 // set labelOffset [sx, sy, sz] 669 // set labelOffset [mode, sx, sy, sz, ax, ay, az] 670 // 671 // where 672 // 673 // sx,sy,sz are screen coord offsets 674 // -- applied after view rotation 675 // -- sy > 0 LOWERS label 676 // ax,ay,az are xyz position (in Angstroms; applied before view rotation) 677 // mode == 0 indicates xyz position is absolute and sx sy sz are Angstroms 678 // mode == 1 indicates xyz position is relative to atom position and sx sy sz are Angstroms 679 // mode == 2 indicates xyz is absolute, and sx sy sz positions are screen pixels 680 // mode == 3 indicates xyz is relative, and sx sy sz positions are screen pixels 681 // defaults: mode == 1; ax = ay = az = 0 682 // 683 // 684 685 /** 686 * PyMOL will use 1 here for pymolOffset[0] for relative, 0 or absolute. Jmol 687 * set labelOffset or set echo offset or measure offset will set -1, when 688 * using {sx sy sz}. 689 * 690 * 691 * @param atomPt 692 * @param screen 693 * @param zSlab 694 * @param pTemp 695 * @param sppm 696 */ getPymolScreenOffset(P3 atomPt, P3i screen, int zSlab, P3 pTemp, float sppm)697 public void getPymolScreenOffset(P3 atomPt, P3i screen, int zSlab, P3 pTemp, 698 float sppm) { 699 float mode = pymolOffset[0]; 700 if (atomPt != null && (Math.abs(mode) % 2) == 1) 701 pTemp.setT(atomPt); 702 else 703 pTemp.set(0, 0, 0); 704 pTemp.add3(pymolOffset[4], pymolOffset[5], pymolOffset[6]); 705 vwr.tm.transformPtScr(pTemp, screen); 706 if (mode == 2 || mode == 3) { 707 screen.x += pymolOffset[1]; 708 screen.y += pymolOffset[2]; 709 screen.z += pymolOffset[3]; 710 } 711 setXYZs(screen.x, screen.y, screen.z, zSlab); 712 setScalePixelsPerMicron(sppm); 713 } 714 715 } 716