// @(#)root/graf:$Name:  $:$Id: TCurlyLine.cxx,v 1.9 2005/08/29 14:43:30 brun Exp $
// Author: Otto Schaile   20/11/99

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//________________________________________________________________________
//
// This class implements curly or wavy polylines typically used to draw Feynman diagrams.
// Amplitudes and wavelengths may be specified in the constructors,
// via commands or interactively from popup menus.
// The class make use of TPolyLine by inheritance, ExecuteEvent methods
// are highly inspired from the methods used in TPolyLine and TArc.
// The picture below has been generated by the tutorial feynman.
//
/* */ //

//________________________________________________________________________

#include "Riostream.h"
#include "TCurlyLine.h"
#include "TROOT.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "TMath.h"

Double_t TCurlyLine::fgDefaultWaveLength = 0.02;
Double_t TCurlyLine::fgDefaultAmplitude  = 0.01; 
Bool_t   TCurlyLine::fgDefaultIsCurly    = kFALSE;   

ClassImp(TCurlyLine)

//______________________________________________________________________________
 TCurlyLine::TCurlyLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t wl, Double_t amp)
{
 // create a new TCurlyLine with starting point (x1, y1), end point (x2,y2)
 // The wavelength and amplitude are given in percent of the pad height

   fX1         = x1;
   fY1         = y1;
   fX2         = x2;
   fY2         = y2;
   fWaveLength = wl;
   fAmplitude  = amp;
   fIsCurly    = fgDefaultIsCurly;
   Build();
}

//______________________________________________________________________________
 void TCurlyLine::Build()
{
//*-*-*-*-*-*-*-*-*-*-*Create a curly (Gluon) or wavy (Gamma) line*-*-*-*-*-*
//*-*                  ===========================================
//---
   Double_t pixeltoX = 1;
   Double_t pixeltoY = 1;
//---
   Double_t wavelengthPix,amplitudePix, lengthPix, hPix;
   Double_t px1, py1, px2, py2;
   if (gPad) {
   	Double_t ww = (Double_t)gPad->GetWw();
   	Double_t wh = (Double_t)gPad->GetWh();
   	Double_t pxrange = gPad->GetAbsWNDC()*ww;
   	Double_t pyrange = - gPad->GetAbsHNDC()*wh;
   	Double_t xrange  = gPad->GetX2() - gPad->GetX1();
   	Double_t yrange  = gPad->GetY2() - gPad->GetY1();

//    pixeltoX  = gPad->GetPixeltoX(); 
//    pixeltoY  = gPad->GetPixeltoY(); 

   	pixeltoX  = xrange / pxrange;
   	pixeltoY  = yrange/pyrange;
      hPix  = TMath::Max(gPad->GetAbsHNDC() * gPad->GetWh(), gPad->GetAbsWNDC() * gPad->GetWw());
      px1      = gPad->XtoAbsPixel(fX1);
      py1      = gPad->YtoAbsPixel(fY1);
      px2      = gPad->XtoAbsPixel(fX2);
      py2      = gPad->YtoAbsPixel(fY2);

      lengthPix = TMath::Sqrt((px2-px1)*(px2-px1) + (py1-py2)*(py1-py2));
      wavelengthPix = hPix*fWaveLength;
      amplitudePix  = hPix*fAmplitude;
   } else {
      wavelengthPix = fWaveLength;
      amplitudePix  = fAmplitude;
      px1           = fX1;
      py1           = fY1;
      px2           = fX2;
      py2           = fY2;
      lengthPix = TMath::Sqrt((px2-px1)*(px2-px1) + (py1-py2)*(py1-py2));
   }
   if(lengthPix <= wavelengthPix){
      Warning("Build","CurlyLine is too short, length %g is < wavelength: %g ",lengthPix,wavelengthPix);
      SetBit(kTooShort);
      return;
   }
// construct the curly / wavy line in pixel coordinates at angle 0
   Double_t anglestep = 40;
   Double_t phimaxle  = TMath::Pi() * 2. / anglestep ;
   Double_t dx        = wavelengthPix / 40;
   Double_t len2pi    = dx * anglestep;

//  make sure there is a piece of straight line a both ends

   Double_t  lengthcycle = 0.5 * len2pi + 2 * amplitudePix;
//   if (fIsCurly) lengthcycle +=  amplitudePix;
   Int_t nperiods = (Int_t)((lengthPix - lengthcycle) / len2pi);
   Double_t restlength = 0.5 * (lengthPix - nperiods * len2pi - lengthcycle);
   fNsteps = (Int_t)(anglestep * nperiods + anglestep / 2 + 4);
   SetPolyLine(fNsteps);
   Double_t *xv = GetX();
   Double_t *yv = GetY();
   xv[0] = 0;          yv[0] = 0;
   xv[1] = restlength; yv[1] = 0;
   Double_t phase =  1.5 * TMath::Pi();
   Double_t x0 = amplitudePix + restlength;
   Int_t i;
   for(i = 2; i < fNsteps-1; i++){
//  distinguish between curly and wavy
      if(fIsCurly) xv[i] = x0 + amplitudePix * TMath::Sin(phase);
      else         xv[i] = x0;
      yv[i]  = amplitudePix*TMath::Cos(phase);
      phase += phimaxle;
      x0    += dx;
   }
   xv[fNsteps-1] = lengthPix; yv[fNsteps-1] = 0;
   
   if (InheritsFrom("TCurlyArc")) return;  // called by TCurlyArc

// rotate object and transform back to user coordinates 
  Double_t angle = TMath::ATan2(py2-py1, px2-px1);
   if(angle < 0) angle += 2*TMath::Pi();

   Double_t cosang = TMath::Cos(angle);
   Double_t sinang = TMath::Sin(angle);
   Double_t xx, yy;

   for(i = 0; i < fNsteps; i++){
      xx = xv[i] * cosang - yv[i] * sinang;
      yy = xv[i] * sinang + yv[i] * cosang;
      if (gPad) {
        xx *= pixeltoX;
        yy *= pixeltoY;
      }
      xv[i] = xx + fX1;
      yv[i] = yy + fY1;
   }
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
  Int_t TCurlyLine::DistancetoPrimitive(Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Compute distance from point px,py to a line*-*-*-*-*-*
//*-*                  ===========================================

   return DistancetoLine(px,py,fX1,fY1,fX2,fY2);
}

//______________________________________________________________________________
 void TCurlyLine::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-*
//*-*                  =========================================
//  This member function is called when a  TCurlyLine is clicked with the locator
//
//  If Left button clicked on one of the line end points, this point
//     follows the cursor until button is released.
//
//  if Middle button clicked, the line is moved parallel to itself
//     until the button is released.
//

   Int_t kMaxDiff = 20;
   static Int_t d1,d2,px1,px2,py1,py2;
   static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
   static Bool_t p1, p2, pL;
   Int_t dx, dy;


   switch (event) {

   case kButton1Down:
      gVirtualX->SetLineColor(-1);
      TAttLine::Modify();  //Change line attributes only if necessary

      // No break !!!

   case kMouseMotion:

      px1 = gPad->XtoAbsPixel(fX1);
      py1 = gPad->YtoAbsPixel(fY1);
      px2 = gPad->XtoAbsPixel(fX2);
      py2 = gPad->YtoAbsPixel(fY2);

      p1 = p2 = pL = kFALSE;

      d1  = TMath::Abs(px1 - px) + TMath::Abs(py1-py); //simply take sum of pixels differences
      if (d1 < kMaxDiff) { //*-*================>OK take point number 1
         px1old = px1; py1old = py1;
         p1 = kTRUE;
         gPad->SetCursor(kPointer);
         return;
      }
      d2  = TMath::Abs(px2 - px) + TMath::Abs(py2-py); //simply take sum of pixels differences
      if (d2 < kMaxDiff) { //*-*================>OK take point number 2
         px2old = px2; py2old = py2;
         p2 = kTRUE;
         gPad->SetCursor(kPointer);
         return;
      }

      pL = kTRUE;
      pxold = px; pyold = py;
      gPad->SetCursor(kMove);

      break;

   case kButton1Motion:

      if (p1) {
         gVirtualX->DrawLine(px1old, py1old, px2, py2);
         gVirtualX->DrawLine(px, py, px2, py2);
         px1old = px;
         py1old = py;
      }
      if (p2) {
         gVirtualX->DrawLine(px1, py1, px2old, py2old);
         gVirtualX->DrawLine(px1, py1, px, py);
         px2old = px;
         py2old = py;
      }
      if (pL) {
         gVirtualX->DrawLine(px1, py1, px2, py2);
         dx = px-pxold;  dy = py-pyold;
         px1 += dx; py1 += dy; px2 += dx; py2 += dy;
         gVirtualX->DrawLine(px1, py1, px2, py2);
         pxold = px;
         pyold = py;
      }
      break;

   case kButton1Up:

      if (p1) {
         fX1 = gPad->AbsPixeltoX(px);
         fY1 = gPad->AbsPixeltoY(py);
      }
      if (p2) {
         fX2 = gPad->AbsPixeltoX(px);
         fY2 = gPad->AbsPixeltoY(py);
      }
      if (pL) {
         fX1 = gPad->AbsPixeltoX(px1);
         fY1 = gPad->AbsPixeltoY(py1);
         fX2 = gPad->AbsPixeltoX(px2);
         fY2 = gPad->AbsPixeltoY(py2);
      }
      Build();
      gPad->Modified();
      gVirtualX->SetLineColor(-1);
   }
}

//_____________________________________________________________________________________
 void TCurlyLine::SavePrimitive(ofstream &out, Option_t *){
    // Save primitive as a C++ statement(s) on output stream out

   if (gROOT->ClassSaved(TCurlyLine::Class())) {
       out<<"   ";
   } else {
       out<<"   TCurlyLine *";
   }
   out<<"curlyline = new TCurlyLine("
     <<fX1<<","<<fY1<<","<<fX2<<","<<fY2<<","
     <<fWaveLength<<","<<fAmplitude<<");"<<endl;
   if (!fIsCurly) {
      out<<"   curlyline->SetWavy();"<<endl;
   }
   SaveLineAttributes(out,"curlyline",1,1,1);
   out<<"   curlyline->Draw();"<<endl;
}

//_____________________________________________________________________________________
 void TCurlyLine::SetCurly()
{
   fIsCurly = kTRUE;
   Build();
}
 void TCurlyLine::SetWavy()
{
   fIsCurly = kFALSE;
   Build();
}
 void TCurlyLine::SetWaveLength(Double_t x)
{
   fWaveLength = x;
   Build();
}
 void TCurlyLine::SetAmplitude(Double_t x)
{
   fAmplitude = x;
   Build();
}
 void TCurlyLine::SetStartPoint(Double_t x, Double_t y)
{
   fX1 = x;
   fY1 = y;
   Build();
}
 void TCurlyLine::SetEndPoint(Double_t x, Double_t y)
{
   fX2 = x;
   fY2 = y;
   Build();
}
//_____________________________________________________________________________________

 void TCurlyLine::SetDefaultWaveLength(Double_t WaveLength)
{
   fgDefaultWaveLength = WaveLength;
}
 void TCurlyLine::SetDefaultAmplitude(Double_t Amplitude)
{
   fgDefaultAmplitude  = Amplitude;
}
 void TCurlyLine::SetDefaultIsCurly(Bool_t IsCurly)
{
   fgDefaultIsCurly    = IsCurly;
}
 Double_t TCurlyLine::GetDefaultWaveLength()
{
   return fgDefaultWaveLength;
}
 Double_t TCurlyLine::GetDefaultAmplitude()
{
   return fgDefaultAmplitude;
}
 Bool_t TCurlyLine::GetDefaultIsCurly()
{
   return fgDefaultIsCurly;
}
     


ROOT page - Class index - Class Hierarchy - 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.