#include "TGLRotateManip.h"
#include "TGLPhysicalShape.h"
#include "TGLCamera.h"
#include "TGLIncludes.h"
#include "TMath.h"
#include "TError.h"
ClassImp(TGLRotateManip);
Double_t TGLRotateManip::Angle(const TGLVector3& v1, const TGLVector3& v2)
{
return TMath::ACos(Dot(v1, v2) / (v1.Mag() * v2.Mag()));
}
Double_t TGLRotateManip::Angle(const TGLVector3& v1, const TGLVector3& v2,
const TGLVector3& ref)
{
TGLVector3 cross = Cross(v1, v2);
if (Dot(cross,ref) > 0.0) {
return Angle(v1, v2);
} else {
return -Angle(v1, v2);
}
}
TGLRotateManip::TGLRotateManip() :
fShallowRing(kFALSE), fShallowFront(kTRUE),
fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
{
}
TGLRotateManip::TGLRotateManip(TGLPhysicalShape* shape) :
TGLManip(shape),
fShallowRing(kFALSE), fShallowFront(kTRUE),
fActiveRingPlane(TGLVector3(1.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fActiveRingCenter(TGLVertex3(0.0, 0.0, 0.0)),
fRingLine(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0)),
fRingLineOld(TGLVertex3(0.0, 0.0, 0.0), TGLVertex3(0.0, 0.0, 0.0))
{
}
TGLRotateManip::~TGLRotateManip()
{
}
void TGLRotateManip::Draw(const TGLCamera& camera) const
{
if (!fShape) {
return;
}
const TGLBoundingBox& box = fShape->BoundingBox();
Double_t baseScale;
TGLVector3 axisScale[3];
CalcDrawScale(box, camera, baseScale, axisScale);
Double_t ringRadius = baseScale*10.0;
TGLPhysicalShape::EManip manip = fShape->GetManip();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
TGLUtil::TDrawQualityScaler hiRes(3);
if (manip & TGLPhysicalShape::kRotateX) {
glPushName(1);
TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, ColorFor(1));
glPopName();
} else {
TGLUtil::DrawRing(box.Center(), box.Axis(0, kTRUE), ringRadius*1.004, TGLUtil::fgGrey);
}
if (manip & TGLPhysicalShape::kRotateY) {
glPushName(2);
TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, ColorFor(2));
glPopName();
} else {
TGLUtil::DrawRing(box.Center(), box.Axis(1, kTRUE), ringRadius*1.002, TGLUtil::fgGrey);
}
if (manip & TGLPhysicalShape::kRotateZ) {
glPushName(3);
TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, ColorFor(3));
glPopName();
} else {
TGLUtil::DrawRing(box.Center(), box.Axis(2, kTRUE), ringRadius, TGLUtil::fgGrey);
}
TGLUtil::DrawSphere(box.Center(), ringRadius/20.0, TGLUtil::fgWhite);
if (fActive) {
if (fShallowRing) {
TGLVertex3 eyeOnRing;
if (fShallowFront) {
eyeOnRing = fActiveRingCenter - (camera.EyeDirection()*ringRadius);
} else {
eyeOnRing = fActiveRingCenter + (camera.EyeDirection()*ringRadius);
}
eyeOnRing = fActiveRingPlane.NearestOn(eyeOnRing);
TGLVector3 arrowDir = Cross(fActiveRingPlane.Norm(), eyeOnRing - fActiveRingCenter);
arrowDir.Normalise();
TGLUtil::DrawLine(eyeOnRing, arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
TGLUtil::DrawLine(eyeOnRing, -arrowDir*ringRadius*1.3, TGLUtil::kLineHeadArrow, baseScale, TGLUtil::fgYellow);
} else {
TGLVector3 activeVector = fRingLine.Vector();
activeVector.Normalise();
activeVector *= ringRadius;
TGLUtil::DrawLine(fRingLine.Start(), activeVector,
TGLUtil::kLineHeadNone, baseScale, TGLUtil::fgYellow);
}
}
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
}
Bool_t TGLRotateManip::HandleButton(const Event_t& event, const TGLCamera& camera)
{
Bool_t captured = TGLManip::HandleButton(event, camera);
if (captured) {
UInt_t axisIndex = fSelectedWidget - 1;
TGLVector3 widgetAxis = fShape->BoundingBox().Axis(axisIndex, kTRUE);
fActiveRingPlane.Set(widgetAxis, fShape->BoundingBox().Center());
fActiveRingCenter.Set(fShape->BoundingBox().Center());
fRingLineOld = fRingLine = CalculateRingLine(fLastMouse, camera);
Double_t planeEyeAngle = Angle(fActiveRingPlane.Norm(), camera.EyeDirection()) - TMath::ASin(1.0);
Double_t shallowDelta = 0.15;
if ((planeEyeAngle > -shallowDelta) && (planeEyeAngle < shallowDelta)) {
fShallowRing = kTRUE;
fShallowFront = kTRUE;
} else {
fShallowRing = kFALSE;
}
}
return captured;
}
Bool_t TGLRotateManip::HandleMotion(const Event_t& event, const TGLCamera& camera)
{
if (fActive) {
TPoint newMouse(event.fX, event.fY);
Double_t angle = CalculateAngleDelta(newMouse, camera);
fShape->Rotate(fActiveRingCenter, fActiveRingPlane.Norm(), angle);
fLastMouse = newMouse;
return kTRUE;
}
return kFALSE;
}
Double_t TGLRotateManip::CalculateAngleDelta(const TPoint& mouse, const TGLCamera& camera)
{
if (fShallowRing) {
std::pair<Bool_t, TGLLine3> nearLineIntersection = Intersection(fActiveRingPlane,
camera.FrustumPlane(TGLCamera::kNear));
if (!nearLineIntersection.first) {
Error("TGLRotateManip::CalculateAngleDelta", "active ring plane parallel to near clip?");
return 1.0;
}
TGLLine3 nearLine = nearLineIntersection.second;
TGLVector3 activePlaneNear = camera.WorldDeltaToViewport(nearLine.Start(), nearLine.Vector());
activePlaneNear.Normalise();
TGLVector3 mouseDelta(mouse.GetX() - fLastMouse.GetX(),
-(mouse.GetY() - fLastMouse.GetY()),
0.0);
Double_t angle = Dot(activePlaneNear, mouseDelta) / 150.0;
if (fShallowFront) {
return -angle;
} else {
return angle;
}
} else {
fRingLineOld = fRingLine;
fRingLine = CalculateRingLine(fLastMouse, camera);
return Angle(fRingLineOld.Vector(), fRingLine.Vector(), fActiveRingPlane.Norm());
}
}
TGLLine3 TGLRotateManip::CalculateRingLine(const TPoint& mouse, const TGLCamera& camera) const
{
TPoint mouseViewport(mouse);
camera.WindowToViewport(mouseViewport);
TGLLine3 viewportProjection = camera.ViewportToWorld(mouseViewport);
std::pair<Bool_t, TGLVertex3> ringPlaneInter = Intersection(fActiveRingPlane, viewportProjection, kTRUE);
if (!ringPlaneInter.first) {
return TGLLine3(fActiveRingCenter, -camera.EyeDirection());
}
return TGLLine3(fActiveRingCenter, ringPlaneInter.second);
}