// @(#)root/g3d:$Name:  $:$Id: TAxis3D.cxx,v 1.10 2002/09/14 16:20:14 brun Exp $
// Author: Valery Fine(fine@mail.cern.ch)   07/01/2000

// ***********************************************************************
// * C++ class library to paint 3D axice "arround" TView object
//                     and zoom 3D objects  as well
// * Copyright(c) 1997~1999  [BNL] Brookhaven National Laboratory, STAR, All rights reserved
// * Author                  Valeri Fine  (fine@bnl.gov)
// * Copyright(c) 1997~1999  Valeri Fine  (fine@bnl.gov)
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// *
// * Permission to use, copy, modify and distribute this software and its
// * documentation for any purpose is hereby granted without fee,
// * provided that the above copyright notice appear in all copies and
// * that both that copyright notice and this permission notice appear
// * in supporting documentation.  Brookhaven National Laboratory makes no
// * representations about the suitability of this software for any
// * purpose.  It is provided "as is" without express or implied warranty.
// ************************************************************************

#include <ctype.h>
#include <assert.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TClass.h"
#include "TAxis3D.h"
#include "TCanvas.h"
#include "TPad.h"
#include "TGaxis.h"
#include "TView.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "TBrowser.h"

//______________________________________________________________________________
//   The 3D axis painter class
//   ==========================
//
//  This class provide up to 3 axice to any 3D ROOT plot and
//  "ZOOM" service.
//  ExecuteEvent() method does provide zooming and moving a projection
//  3D object within TPad client area. With Zoom mode on the user can access
//  TAxis3D context menu and set /change the attributes of axice all together
//  or separately.
//
//  To add the 3D rulers to any 3D view one has to create
//  an instance of this class and Draw it.
//
//   TAxis3D rulers;
//   rulers.Draw();
//
//  One can use a static method to create ruler and attach it to the current gPad
//
//   TAxis3D::ToggleRulers(); // Brings the 3D axice up
//   TAxis3D::ToggleRulers(); // next calls remove the rulers from the TPad etc
//
//   To activate Zoomer one may call
//
//   TAxis3D::ToggleZoom();
//
//  each time one needs move or zoom the image. Then the user can:
//    -  move:
//  

// - zoom: //

// its 3D view with <left-mouse button> press / move. // The "Zoom" deactivates itself just the user release the <left-mouse button> // // To change attributes of the rulers attached to the current Pad, one may // query its pointer first: // // TAxis3D *axis = TAxis3D::GetPadAxis(); // Ask axis pointer // if (axis) { // TAxis3D::ToggleRulers() // To pop axice down // axis->SetLabelColor(kBlue); // Paint the axice labels with blue color // axis->SetAxisColor(kRed); // Paint the axice itself with blue color // TAxis3D::ToggleRulers() // To pop axice up // } // // The attributes of the created axice are affected by the current style // (see TStyle class ) and Set... methods of this class // // For example: // // gStyle->SetAxisColor(kYellow,"X"); // gStyle->SetAxisColor(kYellow,"Y"); // gStyle->SetAxisColor(kYellow,"Z"); // // gStyle->SetLabelColor(kYellow,"X"); // gStyle->SetLabelColor(kYellow,"Y"); // gStyle->SetLabelColor(kYellow,"Z"); // // TAxis3D::ToggleRulers(); // TAxis3D::ToggleRulers(); // // will draw all axice and labels with yellow color. // const Char_t *TAxis3D::rulerName = "axis3druler"; ClassImp(TAxis3D) //______________________________________________________________________________ TAxis3D::TAxis3D() : TNamed(TAxis3D::rulerName,"ruler"){ fSelected = 0; fZoomMode = kFALSE; InitSet(); } //______________________________________________________________________________ TAxis3D::TAxis3D(Option_t *option): TNamed(TAxis3D::rulerName,"ruler") { fSelected = 0; InitSet(); fZoomMode = kFALSE; } //______________________________________________________________________________ TAxis3D::TAxis3D(const TAxis3D &axis) : TNamed(axis) { ((TAxis3D&)axis).Copy(*this); } //______________________________________________________________________________ void TAxis3D::Copy(TObject &obj) { //*-*-*-*-*-*-*Copy this histogram structure to newth1*-*-*-*-*-*-*-*-*-*-*-* //*-* ======================================= TNamed::Copy(obj); for (Int_t i=0;i<2;i++) fAxis[i].Copy(((TAxis3D&)obj).fAxis[i]); } //______________________________________________________________________________ void TAxis3D::InitSet() { fAxis[0].SetName("xaxis"); fAxis[1].SetName("yaxis"); fAxis[2].SetName("zaxis"); fAxis[0].Set(1,0.,1.); fAxis[1].Set(1,0.,1.); fAxis[2].Set(1,0.,1.); UseCurrentStyle(); } //______________________________________________________________________________ void TAxis3D::Browse(TBrowser *b){ // Add all 3 axes to the TBrowser for (Int_t i=0;i<3;i++) b->Add(&fAxis[i],fAxis[i].GetTitle()); } //______________________________________________________________________________ Int_t TAxis3D::DistancetoPrimitive(Int_t px, Int_t py) { //*-*-*-*-*-*-*-*-*-*-*Compute distance from point px,py to a line*-*-*-*-*-* //*-* =========================================== //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* Int_t dist = 9; for (int i=0;i<3;i++) { Int_t axDist = fAxis[i].DistancetoPrimitive(px,py); if (dist > axDist) { dist = axDist; fSelected = &fAxis[i]; } } if (fZoomMode) return 0; else return dist; } //______________________________________________________________________________ void TAxis3D::ExecuteEvent(Int_t event, Int_t px, Int_t py) { //*-*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-* //*-* ========================================= //*-* This member function is called when an axis is clicked with the locator //*-* //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* if (fSelected) fSelected->ExecuteEvent(event,px,py); // Execute action corresponding to the mouse event static Double_t x0, y0, x1, y1; static Int_t pxold, pyold; static Int_t px0, py0; static Int_t linedrawn; if (!fZoomMode) return; // something to zoom ? gPad->SetCursor(kCross); switch (event) { case kButton1Down: gVirtualX->SetLineColor(-1); gPad->TAttLine::Modify(); //Change line attributes only if necessary ((TPad *)gPad)->AbsPixeltoXY(px,py,x0,y0); px0 = px; py0 = py; pxold = px; pyold = py; linedrawn = 0; break; case kButton1Motion: if (linedrawn) gVirtualX->DrawBox(px0, py0, pxold, pyold, TVirtualX::kHollow); pxold = px; pyold = py; linedrawn = 1; gVirtualX->DrawBox(px0, py0, pxold, pyold, TVirtualX::kHollow); break; case kButton1Up: { Int_t i; // gPad->GetCanvas()->FeedbackMode(kFALSE); gPad->SetDoubleBuffer(1); gVirtualX->SetDrawMode(TVirtualX::kCopy); // set drawing mode back to normal (copy) mode TView *view = gPad->GetView(); if (!view) break; // no 3D view yet Double_t min[3],max[3],viewCenter[3],viewCenterNDC[3]; view->GetRange(min,max); for (i =0; i<3;i++) viewCenter[i] = (max[i]+min[i])/2; view->WCtoNDC(viewCenter,viewCenterNDC); // Define the center Double_t center[3],pointNDC[3],size[3],oldSize[3]; ((TPad *)gPad)->AbsPixeltoXY(px,py,x1,y1); pointNDC[0] = (x0+x1)/2; pointNDC[1] = (y0+y1)/2; pointNDC[2] = viewCenterNDC[2]; view->NDCtoWC(pointNDC, center); for (i =0; i<3;i++) oldSize[i] = size[i]= (max[i]-min[i])/2; // If there was a small motion, move the center only, do not change a scale if (TMath::Abs(px-px0)+TMath::Abs(py - py0) > 4 ) { Double_t newEdge[3]; for (i =0; i<3;i++) size[i] = -1; pointNDC[0] = x0; pointNDC[1] = y0; view->NDCtoWC(pointNDC, newEdge); for (i =0; i<3;i++) { Double_t newSize = TMath::Abs(newEdge[i]-center[i]); if ( newSize/oldSize[i] > 0.002) size[i] = TMath::Max(size[i], newSize); else size[i] = oldSize[i]; } pointNDC[0] = x1; pointNDC[1] = y1; view->NDCtoWC(pointNDC, newEdge); for (i =0; i<3;i++) { Double_t newSize = TMath::Abs(newEdge[i]-center[i]); if ( newSize/oldSize[i] > 0.002) size[i] = TMath::Max(size[i], newSize); else size[i] = oldSize[i]; } #if 0 if (fZooms == kMAXZOOMS) fZoom = 0; fZooms++; memcpy(fZoomMin[fZooms],min,3*sizeof(Float_t)); memcpy(fZoomMax[fZooms],max,3*sizeof(Float_t)); #endif } for (i =0; i<3;i++) { max[i] = center[i] + size[i]; min[i] = center[i] - size[i]; } view->SetRange(min,max); SwitchZoom(); gPad->Modified(kTRUE); gPad->Update(); break; } default: break; } } //______________________________________________________________________________ char *TAxis3D::GetObjectInfo(Int_t , Int_t ) const { // Dummy method // returns the const char * to "axis3d" return (char*)"axis3d"; } //______________________________________________________________________________ void TAxis3D::Paint(Option_t *) { // Paint axis over 3D view on the TPad TGaxis axis; PaintAxis(&axis, 90); } //______________________________________________________________________________ void TAxis3D::PaintAxis(TGaxis *axis, Float_t ang) { //*-*-*-*-*-*-*Draw the axis for TView object *-*-*-*-*-*-*-*-*-* //*-* ============================== //*-* The original idea belongs: //*-* //*-* void THistPainter::PaintLegoAxis(TGaxis *axis, Double_t ang) //*-* static Double_t epsil = 0.001; Double_t cosa, sina; Double_t bmin, bmax; Double_t r[24] /* was [3][8] */; Int_t ndiv, i; Double_t x1[3], x2[3], y1[3], y2[3], z1[3], z2[3], av[24] /* was [3][8] */; char chopax[8]; Int_t ix1, ix2, iy1, iy2, iz1, iz2; Double_t rad; //*-*----------------------------------------------------------------------- //-- if (Hopt.System != kCARTESIAN) return ; TView *view = gPad->GetView(); if (!view) { Error("PaintAxis", "no TView in current pad"); return; } rad = TMath::ATan(1.) * 4. / 180.; cosa = TMath::Cos(ang*rad); sina = TMath::Sin(ang*rad); view->AxisVertex(ang, av, ix1, ix2, iy1, iy2, iz1, iz2); for (i = 1; i <= 8; ++i) { r[i*3 - 3] = av[i*3 - 3] + av[i*3 - 2]*cosa; r[i*3 - 2] = av[i*3 - 2]*sina; r[i*3 - 1] = av[i*3 - 1]; } view->WCtoNDC(&r[ix1*3 - 3], x1); view->WCtoNDC(&r[ix2*3 - 3], x2); view->WCtoNDC(&r[iy1*3 - 3], y1); view->WCtoNDC(&r[iy2*3 - 3], y2); view->WCtoNDC(&r[iz1*3 - 3], z1); view->WCtoNDC(&r[iz2*3 - 3], z2); view->SetAxisNDC(x1, x2, y1, y2, z1, z2); Double_t *rmin = view->GetRmin(); Double_t *rmax = view->GetRmax(); axis->SetLineWidth(1); for (i=0;i<3;i++) { //*-*- X axis drawing Double_t ax[2], ay[2]; Bool_t logAx = kFALSE; memset(chopax,0,sizeof(chopax)); switch (i) { case 0 : ax[0] = x1[0]; ax[1] = x2[0]; ay[0] = x1[1]; ay[1] = x2[1]; logAx = gPad->GetLogx(); break; case 1 : if (TMath::Abs(y1[0] - y2[0]) < epsil) y2[0] = y1[0]; ax[0] = y1[0]; ax[1] = y2[0]; ay[0] = y1[1]; ay[1] = y2[1]; logAx = gPad->GetLogy(); break; case 2 : ax[0] = z1[0]; ax[1] = z2[0]; ay[0] = z1[1]; ay[1] = z2[1]; strcpy(chopax, "SDH+="); logAx = gPad->GetLogz(); break; default: assert(0); continue; }; // If the axis is too short - skip it if ( ( TMath::Abs(ax[0] - ax[1]) + TMath::Abs(ay[0] - ay[1])) < epsil ) continue; if (i != 2 ) { if (ax[0] > ax[1]) strcpy(chopax, "SDHV=+"); else strcpy(chopax, "SDHV=-"); } if (i==1 && (TMath::Abs(z1[0] - z2[0]) + TMath::Abs(z1[1] - z2[1])) < epsil) strcpy(chopax, "SDH+="); //*-*- Initialize the axis options if (logAx) { strcat(chopax,"G"); bmin = TMath::Power(10, rmin[i]); bmax = TMath::Power(10, rmax[i]); } else { bmin = rmin[i]; bmax = rmax[i]; } axis->SetLineColor( fAxis[i].GetAxisColor()); axis->SetTextFont( fAxis[i].GetTitleFont()); axis->SetTextColor( fAxis[i].GetTitleColor()); axis->SetTickSize( fAxis[i].GetTickLength()); axis->SetLabelColor( fAxis[i].GetLabelColor()); axis->SetLabelFont( fAxis[i].GetLabelFont()); axis->SetLabelOffset(fAxis[i].GetLabelOffset()+fAxis[i].GetTickLength()); axis->SetLabelSize( fAxis[i].GetLabelSize()); axis->SetTitle( fAxis[i].GetTitle()); axis->SetTitleOffset(fAxis[i].GetTitleOffset()); axis->SetTitleSize( fAxis[i].GetTitleSize()); enum { kCenterTitle = BIT(12) }; // to be removed with the last version of ROOT axis->SetBit(kCenterTitle, fAxis[i].TestBit(kCenterTitle)); //*-*- Initialize the number of divisions. If the //*-*- number of divisions is negative, option 'N' is required. ndiv = fAxis[i].GetNdivisions(); if (ndiv < 0) { ndiv = -ndiv; chopax[6] = 'N'; } //*-*- Option time display is required ? if (fAxis[i].GetTimeDisplay()) { strcat(chopax,"t"); if (strlen(fAxis[i].GetTimeFormat()) == 0) { axis->SetTimeFormat(fAxis[i].ChooseTimeFormat(bmax-bmin)); } else { axis->SetTimeFormat(fAxis[i].GetTimeFormat()); } } axis->SetOption(chopax); axis->PaintAxis(ax[0], ay[0], ax[1], ay[1], bmin, bmax, ndiv, chopax); } } //______________________________________________________________________________ Double_t *TAxis3D::PixeltoXYZ(Double_t px, Double_t py, Double_t *point3D, TView *view) { // Convert "screen pixel" coordinates to some center of 3D WC coordinate // if view and gPad present Double_t *thisPoint = 0; if (!view && gPad) view = gPad->GetView(); if (view) { Double_t x[3] = {px,py,0.5}; // ((TPad *)thisPad)->AbsPixeltoXY(px,py,x[0],x[1]); Double_t min[3], max[3]; view->GetRange(min,max); Int_t i; for (i =0; i<3;i++) min[i] = (max[i]+min[i])/2; view->WCtoNDC(min,max); min[0] = x[0]; min[1] = x[1]; min[2] = max[2]; view->NDCtoWC(min, x); for (i=0;i<3;i++) point3D[i] = x[i]; thisPoint = point3D; } return thisPoint; } //______________________________________________________________________________ void TAxis3D::SavePrimitive(ofstream &out, Option_t *) { // Save primitive as a C++ statement(s) on output stream out // char quote = '"'; // out<<" "<<endl; fAxis[0].SaveAttributes(out,GetName(),"->GetXaxis()"); fAxis[1].SaveAttributes(out,GetName(),"->GetYaxis()"); fAxis[2].SaveAttributes(out,GetName(),"->GetZaxis()"); // out <<GetName()<<"->Draw(" // <<quote<<option<<quote<<");"<<endl; } //______________________________________________________________________________ void TAxis3D::UseCurrentStyle() { //*-*-*-*-*-*Replace current attributes by current style*-*-*-*-* //*-* =========================================== fAxis[0].ResetAttAxis("X"); fAxis[1].ResetAttAxis("Y"); fAxis[2].ResetAttAxis("Z"); fAxis[0].SetTitle("x"); fAxis[0].SetLabelColor(kRed); fAxis[0].SetAxisColor(kRed); fAxis[1].SetLabelColor(kGreen);fAxis[1].SetAxisColor(kGreen); fAxis[2].SetLabelColor(kBlue); fAxis[2].SetAxisColor(kBlue); } //______________________________________________________________________________ Int_t TAxis3D::AxisChoice( Option_t *axis) const { // Return the axis index by its name char achoice = toupper(axis[0]); if (achoice == 'X') return 0; if (achoice == 'Y') return 1; if (achoice == 'Z') return 2; return -1; } //______________________________________________________________________________ Int_t TAxis3D::GetNdivisions( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetNdivisions(); } //______________________________________________________________________________ Color_t TAxis3D::GetAxisColor( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetAxisColor(); } //______________________________________________________________________________ Color_t TAxis3D::GetLabelColor( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetLabelColor(); } //______________________________________________________________________________ Style_t TAxis3D::GetLabelFont( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetLabelFont(); } //______________________________________________________________________________ Float_t TAxis3D::GetLabelOffset( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetLabelOffset(); } //______________________________________________________________________________ Float_t TAxis3D::GetLabelSize( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetLabelSize(); } //______________________________________________________________________________ Float_t TAxis3D::GetTickLength( Option_t *axis) const { Int_t ax = AxisChoice(axis); return fAxis[ax].GetTickLength(); } //______________________________________________________________________________ Float_t TAxis3D::GetTitleOffset( Option_t *axis) const { Int_t ax = AxisChoice(axis); fAxis[ax].GetTitleOffset(); return 0; } //______________________________________________________________________________ #define AXISCHOICE \ Int_t i = AxisChoice(axis); \ Int_t nax = 1; \ if (i == -1) { i = 0; nax = 3;}\ for (Int_t ax=i;ax<nax+i;ax++) //______________________________________________________________________________ void TAxis3D::SetNdivisions(Int_t n, Option_t *axis) { AXISCHOICE {fAxis[ax].SetNdivisions(n);} } //______________________________________________________________________________ void TAxis3D::SetAxisColor(Color_t color, Option_t *axis) { AXISCHOICE {fAxis[ax].SetAxisColor(color);} } //______________________________________________________________________________ void TAxis3D::SetAxisRange(Double_t xmin, Double_t xmax, Option_t *axis) { Int_t ax = AxisChoice(axis); TAxis *theAxis = &fAxis[ax]; Int_t bin1 = theAxis->FindBin(xmin); Int_t bin2 = theAxis->FindBin(xmax); theAxis->SetRange(bin1, bin2); } //______________________________________________________________________________ void TAxis3D::SetLabelColor(Color_t color, Option_t *axis) { AXISCHOICE { fAxis[ax].SetLabelColor(color); } } //______________________________________________________________________________ void TAxis3D::SetLabelFont(Style_t font, Option_t *axis) { AXISCHOICE { fAxis[ax].SetLabelFont(font); } } //______________________________________________________________________________ void TAxis3D::SetLabelOffset(Float_t offset, Option_t *axis) { AXISCHOICE { fAxis[ax].SetLabelOffset(offset); } } //______________________________________________________________________________ void TAxis3D::SetLabelSize(Float_t size, Option_t *axis) { AXISCHOICE { fAxis[ax].SetLabelSize(size); } } //______________________________________________________________________________ void TAxis3D::SetTickLength(Float_t length, Option_t *axis) { AXISCHOICE { fAxis[ax].SetTickLength(length); } } //______________________________________________________________________________ void TAxis3D::SetTitleOffset(Float_t offset, Option_t *axis) { AXISCHOICE { fAxis[ax].SetTitleOffset(offset); } } #undef AXISCHOICE //_______________________________________________________________________________________ TAxis3D *TAxis3D::GetPadAxis(TVirtualPad *pad) { // returns the "pad" Axis3D object pointer if any TObject *obj = 0; TVirtualPad *thisPad=pad; if (!thisPad) thisPad = gPad; if (thisPad) { // Find axis in the current thisPad obj = thisPad->FindObject(TAxis3D::rulerName); if (!(obj && obj->InheritsFrom(Class()->GetName()))) obj = 0; } return (TAxis3D *)obj; } //_______________________________________________________________________________________ TAxis3D *TAxis3D::ToggleRulers(TVirtualPad *pad) { // Turn ON / OFF the "Ruler", TAxis3D object attached // to the current pad TAxis3D *ax = 0; TVirtualPad *thisPad=pad; if (!thisPad) thisPad = gPad; if (thisPad && thisPad->GetView() ) { TAxis3D *a = GetPadAxis(pad); if (a) delete a; else { ax = new TAxis3D; ax->SetBit(kCanDelete); ax->Draw(); } thisPad->Modified(); thisPad->Update(); } return ax; } //_______________________________________________________________________________________ TAxis3D *TAxis3D::ToggleZoom(TVirtualPad *pad) { // Turn ON / OFF the "Ruler" and "zoom mode" of the TAxis3D object attached // to the current pad (if pad = 0; gPad is used "by default") // // User is given a chance to either: // 1. move the center of the 3D scene at the cursor position // 2. zoom view with mouse "drugging" the bounder rectangle with "left" mouse // 3. Change the axuce attributes via TContextMenu with "righ mouse button click" // TAxis3D *ax = 0; TVirtualPad *thisPad=pad; if (!thisPad) thisPad = gPad; if (thisPad && thisPad->GetView()) { // Find axis in the current thisPad TList *l = thisPad->GetListOfPrimitives(); TObject *o = l->FindObject(TAxis3D::rulerName); if (o && o->InheritsFrom(Class()->GetName())) { // Find axis if (o != l->Last()) { // make sure the TAxis3D is the last object of the Pad. l->Remove(o); l->AddLast(o); } ax = (TAxis3D *)o; } else { // There is no ax = new TAxis3D; ax->SetBit(kCanDelete); ax->Draw(); } ax->SwitchZoom(); } return ax; }


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.