    // @(#)root/graf:$Name:  $:$Id: TCurlyLine.cxx,v 1.4 2002/01/24 11:39:28 rdm 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" ClassImp(TCurlyLine) //______________________________________________________________________________ TCurlyLine::TCurlyLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t tl, Double_t rad) { // 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 = tl; fAmplitude = rad; fIsCurly = kTRUE; Build(); } //______________________________________________________________________________ void TCurlyLine::Build() { //*-*-*-*-*-*-*-*-*-*-*Create a curly (Gluon) or wavy (Gamma) line*-*-*-*-*-* //*-* =========================================== Double_t pixwave,pixampl; if (gPad) { Double_t hpixels = gPad->GetAbsHNDC()*gPad->GetWh(); Int_t px1 = gPad->XtoAbsPixel(fX1); Int_t py1 = gPad->YtoAbsPixel(fY1); Int_t px2 = gPad->XtoAbsPixel(fX2); Int_t py2 = gPad->YtoAbsPixel(fY2); Double_t pl2 = Double_t((px2-px1)*(px2-px1) + (py1-py2)*(py1-py2)); Double_t pixlength = TMath::Sqrt(pl2); pixwave = hpixels*fWaveLength/pixlength; pixampl = hpixels*fAmplitude/pixlength; } else { pixwave = fWaveLength; pixampl = fAmplitude; } Double_t anglestep = 20; Double_t phimaxle = TMath::Pi() * 2. / anglestep ; Double_t length = TMath::Sqrt((fX2-fX1)*(fX2-fX1) + (fY2-fY1)*(fY2-fY1)); Double_t ampl = length*pixampl; Double_t wave = length*pixwave; Double_t dx = wave/25; Double_t len2pi = dx * anglestep; if(length <= 4 * ampl){ cout << "CurlyLine:: too short " << length << endl; SetBit(kTooShort); return; } Double_t angle = TMath::ATan2(fY2-fY1, fX2-fX1); if(angle < 0) angle += 2*TMath::Pi(); Double_t lengthcycle = 0.5*len2pi + 2*ampl; Int_t nperiods = (Int_t)((length - lengthcycle) / len2pi); Double_t restlenght = 0.5 * (length - 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] = restlenght; yv[1] = 0; Double_t phase = 1.5 * TMath::Pi(); Double_t x0 = ampl + restlenght; Int_t i; for(i = 2; i < fNsteps-1; i++){ // distinguish between curly and wavy if(fIsCurly) xv[i] = x0 + ampl*TMath::Sin(phase); else xv[i] = x0; yv[i] = ampl*TMath::Cos(phase); phase += phimaxle; x0 += dx; } xv[fNsteps-1] = length; yv[fNsteps-1] = 0; 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; 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, L; 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 = L = 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; } L = 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 (L) { 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 (L) { 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(); }