#include "TGLAutoRotator.h"
#include "TGLPhysicalShape.h"
#include "TGLLogicalShape.h"
#include "TGLViewer.h"
#include "TGLCamera.h"
#include "TGLScene.h"
#include "TMath.h"
#include "TTimer.h"
#include "TStopwatch.h"
ClassImp(TGLAutoRotator);
TGLAutoRotator::TGLAutoRotator(TGLViewer* v) :
fViewer(v), fCamera(0),
fTimer(new TTimer), fWatch(new TStopwatch),
fRotateScene(kFALSE),
fDeltaPhi(0.005),
fDt (0.01),
fWPhi (0.40),
fWTheta(0.15), fATheta(0.5),
fWDolly(0.30), fADolly(0.4),
fTimerRunning(kFALSE),
fImageCount(0), fImageAutoSave(kFALSE),
fImageGUIBaseName("animation"), fImageGUIOutMode(1)
{
fTimer->Connect("Timeout()", "TGLAutoRotator", this, "Timeout()");
}
TGLAutoRotator::~TGLAutoRotator()
{
delete fWatch;
delete fTimer;
}
void TGLAutoRotator::SetDt(Double_t dt)
{
fDt = TMath::Range(0.01, 1.0, dt);
if (fTimerRunning)
{
fTimer->SetTime(TMath::Nint(1000*fDt));
fTimer->Reset();
}
}
void TGLAutoRotator::SetATheta(Double_t a)
{
a = TMath::Range(0.01, 1.0, a);
if (fTimerRunning)
{
fThetaA0 = fThetaA0 * a / fATheta;
}
fATheta = a;
}
void TGLAutoRotator::SetADolly(Double_t a)
{
a = TMath::Range(0.01, 1.0, a);
if (fTimerRunning)
{
fDollyA0 = fDollyA0 * a / fADolly;
}
fADolly = a;
}
void TGLAutoRotator::Start()
{
if (fTimerRunning)
{
Stop();
}
fCamera = & fViewer->CurrentCamera();
fThetaA0 = fATheta * TMath::PiOver2();
fDollyA0 = fADolly * fCamera->GetCamTrans().GetBaseVec(4).Mag();
fTimerRunning = kTRUE;
fTimer->SetTime(TMath::Nint(1000*fDt));
fTimer->Reset();
fTimer->TurnOn();
fWatch->Start();
}
void TGLAutoRotator::Stop()
{
if (fTimerRunning)
{
fWatch->Stop();
fTimer->TurnOff();
fTimerRunning = kFALSE;
}
}
void TGLAutoRotator::Timeout()
{
if (!fTimerRunning || gTQSender != fTimer)
{
Error("Timeout", "Not running or not called via timer.");
return;
}
using namespace TMath;
fWatch->Stop();
Double_t time = fWatch->RealTime();
fWatch->Continue();
if (fRotateScene) {
RotateScene();
} else {
Double_t delta_p = fWPhi*fDt;
Double_t delta_t = fThetaA0*fWTheta*Cos(fWTheta*time)*fDt;
Double_t delta_d = fDollyA0*fWDolly*Cos(fWDolly*time)*fDt;
Double_t th = fCamera->GetTheta();
if (th + delta_t > 3.0 || th + delta_t < 0.1416)
delta_t = 0;
fCamera->RotateRad(delta_t, delta_p);
fCamera->RefCamTrans().MoveLF(1, -delta_d);
}
fViewer->RequestDraw(TGLRnrCtx::kLODHigh);
if (fImageAutoSave)
{
TString filename;
if (fImageName.Contains("%"))
{
filename.Form(fImageName, fImageCount);
}
else
{
filename = fImageName;
}
fViewer->SavePicture(filename);
++fImageCount;
}
}
void TGLAutoRotator::StartImageAutoSaveAnimatedGif(const TString& filename)
{
if ( ! filename.Contains(".gif+"))
{
Error("StartImageAutoSaveAnimatedGif", "Name should end with '.gif+'. Not starting.");
return;
}
fImageName = filename;
fImageCount = 0;
fImageAutoSave = kTRUE;
}
void TGLAutoRotator::StartImageAutoSave(const TString& filename)
{
if ( ! filename.Contains("%"))
{
Error("StartImageAutoSave", "Name should include a '%%' character, like 'image-%%05d.png'. Not starting.");
return;
}
fImageName = filename;
fImageCount = 0;
fImageAutoSave = kTRUE;
}
void TGLAutoRotator::StopImageAutoSave()
{
fImageAutoSave = kFALSE;
}
void TGLAutoRotator::SetImageGUIOutMode(Int_t m)
{
if (m < 1 || m > 2)
{
Warning("SetImageGUIOutMode", "Invalid value, ignoring");
return;
}
fImageGUIOutMode = m;
}
void TGLAutoRotator::StartImageAutoSaveWithGUISettings()
{
if (fImageGUIOutMode == 1)
{
TString name = fImageGUIBaseName + ".gif+";
StartImageAutoSaveAnimatedGif(name);
}
else if (fImageGUIOutMode == 2)
{
TString name = fImageGUIBaseName + "-%05d.png";
StartImageAutoSave(name);
}
else
{
Warning("StartImageAutoSaveWithGUISettings", "Unsupported mode '%d'.", fImageGUIOutMode);
}
}
void TGLAutoRotator::RotateScene()
{
TGLViewer::SceneInfoList_t & scenes = fViewer->fScenes;
TGLViewer::SceneInfoList_i sceneIter = scenes.begin();
for (; sceneIter != scenes.end(); ++sceneIter) {
TGLScene::TSceneInfo *sceneInfo = dynamic_cast<TGLScene::TSceneInfo *>(*sceneIter);
if (sceneInfo) {
TGLPhysicalShape *axisShape = 0;
TGLScene::ShapeVec_i shapeIter = sceneInfo->fShapesOfInterest.begin();
for (; shapeIter != sceneInfo->fShapesOfInterest.end(); ++shapeIter) {
TGLPhysicalShape * const testShape = const_cast<TGLPhysicalShape *>(*shapeIter);
if (testShape && testShape->GetLogical()->ID()->TestBit(13)) {
axisShape = testShape;
break;
}
}
TGLVector3 axis;
TGLVertex3 center;
if (!axisShape) {
const TGLBoundingBox &bbox = sceneInfo->GetTransformedBBox();
axis = bbox.Axis(2);
center = bbox.Center();
} else {
axis = axisShape->BoundingBox().Axis(2);
center = axisShape->BoundingBox().Center();
}
shapeIter = sceneInfo->fShapesOfInterest.begin();
for (; shapeIter != sceneInfo->fShapesOfInterest.end(); ++shapeIter) {
if (TGLPhysicalShape * const shape = const_cast<TGLPhysicalShape *>(*shapeIter))
shape->Rotate(center, axis, fDeltaPhi);
}
}
}
}