1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2009-06-26 10:56:39 -0500 (Fri, 26 Jun 2009) $ 4 * $Revision: 11127 $ 5 * 6 * Copyright (C) 2003-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 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.viewer; 25 26 27 import java.util.Map; 28 29 30 import org.jmol.script.T; 31 import org.jmol.thread.JmolThread; 32 import org.jmol.util.BSUtil; 33 //import javajs.util.List; 34 35 import org.jmol.api.Interface; 36 import javajs.util.BS; 37 import org.jmol.modelset.ModelSet; 38 39 public class AnimationManager { 40 41 public JmolThread animationThread; 42 public Viewer vwr; 43 AnimationManager(Viewer vwr)44 AnimationManager(Viewer vwr) { 45 this.vwr = vwr; 46 } 47 48 // used by AnimationThread, Viewer, or StateCreator: 49 50 public boolean animationOn; 51 public int animationFps; // set in stateManager 52 public int firstFrameDelayMs; 53 public int lastFrameDelayMs; 54 setAnimationOn(boolean animationOn)55 public void setAnimationOn(boolean animationOn) { 56 if (animationOn == this.animationOn) 57 return; 58 59 if (!animationOn || vwr.headless) { 60 stopThread(false); 61 return; 62 } 63 if (!vwr.tm.spinOn) 64 vwr.refresh(Viewer.REFRESH_SYNC_MASK, "Anim:setAnimationOn"); 65 setAnimationRange(-1, -1); 66 resumeAnimation(); 67 } 68 stopThread(boolean isPaused)69 public void stopThread(boolean isPaused) { 70 boolean stopped = false; 71 if (animationThread != null) { 72 animationThread.interrupt(); 73 animationThread = null; 74 stopped = true; 75 } 76 animationPaused = isPaused; 77 if (stopped && !vwr.tm.spinOn) 78 vwr.refresh(Viewer.REFRESH_SYNC_MASK, "Viewer:setAnimationOff"); 79 animation(false); 80 //stopModulationThread(); 81 vwr.setStatusFrameChanged(false, false); 82 83 } 84 setAnimationNext()85 public boolean setAnimationNext() { 86 return setAnimationRelative(animationDirection); 87 } 88 currentIsLast()89 public boolean currentIsLast() { 90 return (isMovie ? lastFramePainted == caf 91 : lastModelPainted == cmi); 92 } 93 currentFrameIs(int f)94 public boolean currentFrameIs(int f) { 95 int i = cmi; 96 return (morphCount == 0 ? i == f : Math.abs(currentMorphModel - f) < 0.001f); 97 } 98 99 // required by Viewer or stateCreator 100 101 // used by StateCreator or Viewer: 102 103 final static int FRAME_FIRST = -1; 104 final static int FRAME_LAST = 1; 105 final static int MODEL_CURRENT = 0; 106 107 final BS bsVisibleModels = new BS(); 108 109 public int animationReplayMode = T.once; 110 111 BS bsDisplay; 112 113 int[] animationFrames; 114 115 public boolean isMovie; 116 boolean animationPaused; 117 118 /** 119 * current model index 120 * 121 */ 122 public int cmi; 123 124 /** 125 * current animation frame 126 * 127 */ 128 int caf; 129 int morphCount; 130 int animationDirection = 1; 131 int currentDirection = 1; 132 int firstFrameIndex; 133 int lastFrameIndex; 134 int frameStep; 135 int backgroundModelIndex = -1; 136 137 float currentMorphModel; 138 float firstFrameDelay; 139 float lastFrameDelay = 1; 140 clear()141 void clear() { 142 setMovie(null); 143 initializePointers(0); 144 setAnimationOn(false); 145 setModel(0, true); 146 currentDirection = 1; 147 cai = -1; 148 setAnimationDirection(1); 149 setAnimationFps(10); 150 setAnimationReplayMode(T.once, 0, 0); 151 initializePointers(0); 152 } 153 getModelSpecial(int i)154 String getModelSpecial(int i) { 155 switch (i) { 156 case FRAME_FIRST: 157 if (animationFrames != null) 158 return "1"; 159 i = firstFrameIndex; 160 break; 161 case MODEL_CURRENT: 162 if (morphCount > 0) 163 return "-" + (1 + currentMorphModel); 164 i = cmi; 165 break; 166 case FRAME_LAST: 167 if (animationFrames != null) 168 return "" + animationFrames.length; 169 i = lastFrameIndex; 170 break; 171 } 172 return vwr.getModelNumberDotted(i); 173 } 174 setDisplay(BS bs)175 void setDisplay(BS bs) { 176 bsDisplay = (bs == null || bs.isEmpty() ? null : BSUtil.copy(bs)); 177 } 178 setMorphCount(int n)179 public void setMorphCount(int n) { 180 morphCount = (isMovie ? 0 : n); // for now -- no morphing in movies 181 } 182 morph(float modelIndex)183 public void morph(float modelIndex) { 184 int m = (int) modelIndex; 185 if (Math.abs(m - modelIndex) < 0.001f) 186 modelIndex = m; 187 else if (Math.abs(m - modelIndex) > 0.999f) 188 modelIndex = m = m + 1; 189 float f = modelIndex - m; 190 m -= 1; 191 if (f == 0) { 192 currentMorphModel = m; 193 setModel(m, true); 194 return; 195 } 196 int m1; 197 setModel(m, true); 198 m1 = m + 1; 199 currentMorphModel = m + f; 200 if (m1 == m || m1 < 0 || m < 0) 201 return; 202 vwr.ms.morphTrajectories(m, m1, f); 203 } 204 setModel(int modelIndex, boolean clearBackgroundModel)205 void setModel(int modelIndex, boolean clearBackgroundModel) { 206 if (modelIndex < 0) 207 stopThread(false); 208 int formerModelIndex = cmi; 209 ModelSet modelSet = vwr.ms; 210 int modelCount = (modelSet == null ? 0 : modelSet.mc); 211 if (modelCount == 1) 212 cmi = modelIndex = 0; 213 else if (modelIndex < 0 || modelIndex >= modelCount) 214 modelIndex = -1; 215 String ids = null; 216 boolean isSameSource = false; 217 if (cmi != modelIndex) { 218 if (modelCount > 0) { 219 ModelSet ms = vwr.ms; 220 boolean toDataModel = ms.isJmolDataFrameForModel(modelIndex); 221 boolean fromDataModel = ms.isJmolDataFrameForModel(cmi); 222 if (fromDataModel) 223 ms.setJmolDataFrame(null, -1, cmi); 224 if (cmi != -1) 225 vwr.saveModelOrientation(); 226 if (fromDataModel || toDataModel) { 227 ids = ms.getJmolFrameType(modelIndex) 228 + " " + modelIndex + " <-- " 229 + " " + cmi + " " 230 + ms.getJmolFrameType(cmi); 231 232 isSameSource = (ms.getJmolDataSourceFrame(modelIndex) == ms 233 .getJmolDataSourceFrame(cmi)); 234 } 235 } 236 cmi = modelIndex; 237 if (ids != null) { 238 if (modelIndex >= 0) 239 vwr.restoreModelOrientation(modelIndex); 240 if (isSameSource && (ids.indexOf("quaternion") >= 0 241 || ids.indexOf("plot") < 0 242 && ids.indexOf("ramachandran") < 0 243 && ids.indexOf(" property ") < 0)) { 244 vwr.restoreModelRotation(formerModelIndex); 245 } 246 } 247 } 248 setViewer(clearBackgroundModel); 249 } 250 setBackgroundModelIndex(int modelIndex)251 void setBackgroundModelIndex(int modelIndex) { 252 ModelSet modelSet = vwr.ms; 253 if (modelSet == null || modelIndex < 0 || modelIndex >= modelSet.mc) 254 modelIndex = -1; 255 backgroundModelIndex = modelIndex; 256 if (modelIndex >= 0) 257 vwr.ms.setTrajectory(modelIndex); 258 vwr.setTainted(true); 259 setFrameRangeVisible(); 260 } 261 initializePointers(int frameStep)262 void initializePointers(int frameStep) { 263 firstFrameIndex = 0; 264 lastFrameIndex = (frameStep == 0 ? 0 : getFrameCount()) - 1; 265 this.frameStep = frameStep; 266 vwr.setFrameVariables(); 267 } 268 setAnimationDirection(int animationDirection)269 public void setAnimationDirection(int animationDirection) { 270 this.animationDirection = animationDirection; 271 //if (animationReplayMode != ANIMATION_LOOP) 272 //currentDirection = 1; 273 } 274 setAnimationFps(int fps)275 void setAnimationFps(int fps) { 276 if (fps < 1) 277 fps = 1; 278 if (fps > 50) 279 fps = 50; 280 animationFps = fps; 281 vwr.setFrameVariables(); 282 } 283 284 // 0 = once 285 // 1 = loop 286 // 2 = palindrome 287 setAnimationReplayMode(int animationReplayMode, float firstFrameDelay, float lastFrameDelay)288 public void setAnimationReplayMode(int animationReplayMode, 289 float firstFrameDelay, 290 float lastFrameDelay) { 291 this.firstFrameDelay = firstFrameDelay > 0 ? firstFrameDelay : 0; 292 firstFrameDelayMs = (int)(this.firstFrameDelay * 1000); 293 this.lastFrameDelay = lastFrameDelay > 0 ? lastFrameDelay : 0; 294 lastFrameDelayMs = (int)(this.lastFrameDelay * 1000); 295 this.animationReplayMode = animationReplayMode; 296 vwr.setFrameVariables(); 297 } 298 setAnimationRange(int framePointer, int framePointer2)299 void setAnimationRange(int framePointer, int framePointer2) { 300 int frameCount = getFrameCount(); 301 if (framePointer < 0) framePointer = 0; 302 if (framePointer2 < 0) framePointer2 = frameCount; 303 if (framePointer >= frameCount) framePointer = frameCount - 1; 304 if (framePointer2 >= frameCount) framePointer2 = frameCount - 1; 305 firstFrameIndex = framePointer; 306 currentMorphModel = firstFrameIndex; 307 lastFrameIndex = framePointer2; 308 frameStep = (framePointer2 < framePointer ? -1 : 1); 309 rewindAnimation(); 310 } 311 pauseAnimation()312 void pauseAnimation() { 313 stopThread(true); 314 } 315 reverseAnimation()316 void reverseAnimation() { 317 currentDirection = -currentDirection; 318 if (!animationOn) 319 resumeAnimation(); 320 } 321 repaintDone()322 void repaintDone() { 323 lastModelPainted = cmi; 324 lastFramePainted = caf; 325 } 326 resumeAnimation()327 void resumeAnimation() { 328 if(cmi < 0) 329 setAnimationRange(firstFrameIndex, lastFrameIndex); 330 if (getFrameCount() <= 1) { 331 animation(false); 332 return; 333 } 334 animation(true); 335 animationPaused = false; 336 if (animationThread == null) { 337 intAnimThread++; 338 animationThread = (JmolThread) Interface.getOption("thread.AnimationThread", vwr, "script"); 339 animationThread.setManager(this, vwr, new int[] {firstFrameIndex, lastFrameIndex, intAnimThread} ); 340 animationThread.start(); 341 } 342 } 343 setAnimationLast()344 void setAnimationLast() { 345 setFrame(animationDirection > 0 ? lastFrameIndex : firstFrameIndex); 346 } 347 rewindAnimation()348 void rewindAnimation() { 349 setFrame(animationDirection > 0 ? firstFrameIndex : lastFrameIndex); 350 currentDirection = 1; 351 vwr.setFrameVariables(); 352 } 353 setAnimationPrevious()354 boolean setAnimationPrevious() { 355 return setAnimationRelative(-animationDirection); 356 } 357 getAnimRunTimeSeconds()358 float getAnimRunTimeSeconds() { 359 int frameCount = getFrameCount(); 360 if (firstFrameIndex == lastFrameIndex || lastFrameIndex < 0 361 || firstFrameIndex < 0 || lastFrameIndex >= frameCount 362 || firstFrameIndex >= frameCount) 363 return 0; 364 int i0 = Math.min(firstFrameIndex, lastFrameIndex); 365 int i1 = Math.max(firstFrameIndex, lastFrameIndex); 366 float nsec = 1f * (i1 - i0) / animationFps + firstFrameDelay 367 + lastFrameDelay; 368 for (int i = i0; i <= i1; i++) 369 nsec += vwr.ms.getFrameDelayMs(modelIndexForFrame(i)) / 1000f; 370 return nsec; 371 } 372 373 /** 374 * support for PyMOL movies and 375 * anim FRAMES [....] 376 * 377 * currently no support for scripted movies 378 * 379 * @param info 380 */ setMovie(Map<String, Object> info)381 public void setMovie(Map<String, Object> info) { 382 isMovie = (info != null && info.get("scripts") == null); 383 if (isMovie) { 384 animationFrames = (int[]) info.get("frames"); 385 if (animationFrames == null || animationFrames.length == 0) { 386 isMovie = false; 387 } else { 388 caf = ((Integer) info.get("currentFrame")).intValue(); 389 if (caf < 0 || caf >= animationFrames.length) 390 caf = 0; 391 } 392 setFrame(caf); 393 } 394 if (!isMovie) { 395 //movie = null; 396 animationFrames = null; 397 } 398 vwr.setBooleanProperty("_ismovie", isMovie); 399 bsDisplay = null; 400 currentMorphModel = morphCount = 0; 401 vwr.setFrameVariables(); 402 } 403 modelIndexForFrame(int i)404 int modelIndexForFrame(int i) { 405 return (isMovie ? animationFrames[i] - 1 : i); 406 } 407 getFrameCount()408 public int getFrameCount() { 409 return (isMovie ? animationFrames.length : vwr.ms.mc); 410 } 411 setFrame(int i)412 public void setFrame(int i) { 413 try { 414 if (isMovie) { 415 int iModel = modelIndexForFrame(i); 416 caf = i; 417 i = iModel; 418 } else { 419 caf = i; 420 } 421 setModel(i, true); 422 } catch (Exception e) { 423 // ignore 424 } 425 } 426 427 // private methods and fields 428 429 private int lastFramePainted; 430 private int lastModelPainted; 431 private int intAnimThread; 432 private int cai = -1; 433 getUnitCellAtomIndex()434 public int getUnitCellAtomIndex() { 435 return cai; 436 } 437 setUnitCellAtomIndex(int iAtom)438 public void setUnitCellAtomIndex(int iAtom) { 439 cai = iAtom; 440 } 441 442 setViewer(boolean clearBackgroundModel)443 private void setViewer(boolean clearBackgroundModel) { 444 vwr.ms.setTrajectory(cmi); 445 vwr.tm.setFrameOffset(cmi); 446 if (cmi == -1 && clearBackgroundModel) 447 setBackgroundModelIndex(-1); 448 vwr.setTainted(true); 449 int nDisplay = setFrameRangeVisible(); 450 vwr.setStatusFrameChanged(false, false); 451 if (!vwr.g.selectAllModels) 452 setSelectAllSubset(nDisplay < 2); 453 } 454 455 void setSelectAllSubset(boolean justOne) { 456 if (vwr.ms != null) 457 vwr.slm.setSelectionSubset(justOne ? vwr.ms 458 .getModelAtomBitSetIncludingDeleted(cmi, true) : vwr.ms 459 .getModelAtomBitSetIncludingDeletedBs(bsVisibleModels)); 460 } 461 462 private int setFrameRangeVisible() { 463 int nDisplayed = 0; 464 bsVisibleModels.clearAll(); 465 if (backgroundModelIndex >= 0) { 466 bsVisibleModels.set(backgroundModelIndex); 467 nDisplayed = 1; 468 } 469 if (cmi >= 0) { 470 bsVisibleModels.set(cmi); 471 return ++nDisplayed; 472 } 473 if (frameStep == 0) 474 return nDisplayed; 475 int frameDisplayed = 0; 476 nDisplayed = 0; 477 for (int iframe = firstFrameIndex; iframe != lastFrameIndex; iframe += frameStep) { 478 int i = modelIndexForFrame(iframe); 479 if (!vwr.ms.isJmolDataFrameForModel(i)) { 480 bsVisibleModels.set(i); 481 nDisplayed++; 482 frameDisplayed = iframe; 483 } 484 } 485 int i = modelIndexForFrame(lastFrameIndex); 486 if (firstFrameIndex == lastFrameIndex || !vwr.ms.isJmolDataFrameForModel(i) 487 || nDisplayed == 0) { 488 bsVisibleModels.set(i); 489 if (nDisplayed == 0) 490 firstFrameIndex = lastFrameIndex; 491 nDisplayed = 0; 492 } 493 if (nDisplayed == 1 && cmi < 0) 494 setFrame(frameDisplayed); 495 return nDisplayed; 496 } 497 animation(boolean TF)498 private void animation(boolean TF) { 499 animationOn = TF; 500 vwr.setBooleanProperty("_animating", TF); 501 } 502 setAnimationRelative(int direction)503 private boolean setAnimationRelative(int direction) { 504 int frameStep = getFrameStep(direction); 505 int thisFrame = (isMovie ? caf : cmi); 506 int frameNext = thisFrame + frameStep; 507 float morphStep = 0f, nextMorphFrame = 0f; 508 boolean isDone; 509 if (morphCount > 0) { 510 morphStep = 1f / (morphCount + 1); 511 nextMorphFrame = currentMorphModel + frameStep * morphStep; 512 isDone = isNotInRange(nextMorphFrame); 513 } else { 514 isDone = isNotInRange(frameNext); 515 } 516 if (isDone) { 517 switch (animationReplayMode) { 518 case T.once: 519 return false; 520 case T.loop: 521 nextMorphFrame = frameNext = (animationDirection == currentDirection ? firstFrameIndex 522 : lastFrameIndex); 523 break; 524 case T.palindrome: 525 currentDirection = -currentDirection; 526 frameNext -= 2 * frameStep; 527 nextMorphFrame -= 2 * frameStep * morphStep; 528 } 529 } 530 //Logger.debug("next="+modelIndexNext+" dir="+currentDirection+" isDone="+isDone); 531 //System.out.println("setAnimRel dir=" + direction + " step=" + frameStep + " this=" + thisFrame + " next=" + frameNext + " morphcount=" + morphCount + " done=" + isDone + " mode=" + animationReplayMode); 532 if (morphCount < 1) { 533 if (frameNext < 0 || frameNext >= getFrameCount()) 534 return false; 535 setFrame(frameNext); 536 return true; 537 } 538 morph(nextMorphFrame + 1); 539 return true; 540 } 541 isNotInRange(float frameNext)542 private boolean isNotInRange(float frameNext) { 543 float f = frameNext - 0.001f; 544 return (f > firstFrameIndex && f > lastFrameIndex 545 || (f = frameNext + 0.001f) < firstFrameIndex 546 && f < lastFrameIndex); 547 } 548 getFrameStep(int direction)549 private int getFrameStep(int direction) { 550 return frameStep * direction * currentDirection; 551 } 552 553 554 } 555