Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TCurlyLine.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Otto Schaile 20/11/99
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TCurlyLine
13 \ingroup BasicGraphics
14 
15 Implements curly or wavy polylines used to draw Feynman diagrams.
16 
17 Amplitudes and wavelengths may be specified in the constructors,
18 via commands or interactively from popup menus.
19 The class make use of TPolyLine by inheritance, ExecuteEvent methods
20 are highly inspired from the methods used in TPolyLine and TArc.
21 The picture below has been generated by the tutorial feynman.
22 
23 Begin_Macro(source)
24 ../../../tutorials/graphics/feynman.C
25 End_Macro
26 */
27 
28 #include "Riostream.h"
29 #include "TCurlyLine.h"
30 #include "TROOT.h"
31 #include "TVirtualPad.h"
32 #include "TVirtualX.h"
33 #include "TMath.h"
34 #include "TLine.h"
35 #include "TPoint.h"
36 
37 Double_t TCurlyLine::fgDefaultWaveLength = 0.02;
38 Double_t TCurlyLine::fgDefaultAmplitude = 0.01;
39 Bool_t TCurlyLine::fgDefaultIsCurly = kTRUE;
40 
41 ClassImp(TCurlyLine);
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Default constructor.
45 
46 TCurlyLine::TCurlyLine()
47 {
48  fX1 = 0.;
49  fY1 = 0.;
50  fX2 = 0.;
51  fY2 = 0.;
52  fWaveLength = 0.;
53  fAmplitude = 0.;
54  fIsCurly = fgDefaultIsCurly;
55  fNsteps = 0;
56 }
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 /// Create a new TCurlyLine with starting point (x1, y1), end point (x2,y2).
60 /// The wavelength and amplitude are given in percent of the pad height.
61 
62 TCurlyLine::TCurlyLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t wl, Double_t amp)
63 {
64  fX1 = x1;
65  fY1 = y1;
66  fX2 = x2;
67  fY2 = y2;
68  fWaveLength = wl;
69  fAmplitude = amp;
70  fIsCurly = fgDefaultIsCurly;
71  Build();
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Create a curly (Gluon) or wavy (Gamma) line.
76 
77 void TCurlyLine::Build()
78 {
79  Double_t pixeltoX = 1;
80  Double_t pixeltoY = 1;
81 
82  Double_t wavelengthPix,amplitudePix, lengthPix, hPix;
83  Double_t px1, py1, px2, py2;
84  if (gPad) {
85  Double_t ww = (Double_t)gPad->GetWw();
86  Double_t wh = (Double_t)gPad->GetWh();
87  Double_t pxrange = gPad->GetAbsWNDC()*ww;
88  Double_t pyrange = - gPad->GetAbsHNDC()*wh;
89  Double_t xrange = gPad->GetX2() - gPad->GetX1();
90  Double_t yrange = gPad->GetY2() - gPad->GetY1();
91  pixeltoX = xrange / pxrange;
92  pixeltoY = yrange/pyrange;
93  hPix = TMath::Max(gPad->GetAbsHNDC() * gPad->GetWh(), gPad->GetAbsWNDC() * gPad->GetWw());
94  px1 = gPad->XtoAbsPixel(fX1);
95  py1 = gPad->YtoAbsPixel(fY1);
96  px2 = gPad->XtoAbsPixel(fX2);
97  py2 = gPad->YtoAbsPixel(fY2);
98 
99  lengthPix = TMath::Sqrt((px2-px1)*(px2-px1) + (py1-py2)*(py1-py2));
100  wavelengthPix = hPix*fWaveLength;
101  amplitudePix = hPix*fAmplitude;
102  } else {
103  wavelengthPix = fWaveLength;
104  amplitudePix = fAmplitude;
105  px1 = fX1;
106  py1 = fY1;
107  px2 = fX2;
108  py2 = fY2;
109  lengthPix = TMath::Sqrt((px2-px1)*(px2-px1) + (py1-py2)*(py1-py2));
110  }
111  // construct the curly / wavy line in pixel coordinates at angle 0
112  Double_t anglestep = 40;
113  Double_t phimaxle = TMath::Pi() * 2. / anglestep ;
114  Double_t dx = wavelengthPix / 40;
115  Double_t len2pi = dx * anglestep;
116 
117  // make sure there is a piece of straight line a both ends
118 
119  Double_t lengthcycle = 0.5 * len2pi + 2 * amplitudePix;
120  // if (fIsCurly) lengthcycle += amplitudePix;
121  Int_t nperiods = (Int_t)((lengthPix - lengthcycle) / len2pi);
122  Double_t restlength = 0.5 * (lengthPix - nperiods * len2pi - lengthcycle);
123  fNsteps = (Int_t)(anglestep * nperiods + anglestep / 2 + 4);
124  if (fNsteps < 2) fNsteps = 2;
125  SetPolyLine(fNsteps);
126  Double_t *xv = GetX();
127  Double_t *yv = GetY();
128  xv[0] = 0; yv[0] = 0;
129  xv[1] = restlength; yv[1] = 0;
130  Double_t phase = 1.5 * TMath::Pi();
131  Double_t x0 = amplitudePix + restlength;
132  Int_t i;
133  for(i = 2; i < fNsteps-1; i++){
134  // distinguish between curly and wavy
135  if (fIsCurly) xv[i] = x0 + amplitudePix * TMath::Sin(phase);
136  else xv[i] = x0;
137  yv[i] = amplitudePix*TMath::Cos(phase);
138  phase += phimaxle;
139  x0 += dx;
140  }
141  xv[fNsteps-1] = lengthPix; yv[fNsteps-1] = 0;
142 
143  if (InheritsFrom("TCurlyArc")) return; // called by TCurlyArc
144 
145  // rotate object and transform back to user coordinates
146  Double_t angle = TMath::ATan2(py2-py1, px2-px1);
147  if (angle < 0) angle += 2*TMath::Pi();
148 
149  Double_t cosang = TMath::Cos(angle);
150  Double_t sinang = TMath::Sin(angle);
151  Double_t xx, yy;
152 
153  for(i = 0; i < fNsteps; i++){
154  xx = xv[i] * cosang - yv[i] * sinang;
155  yy = xv[i] * sinang + yv[i] * cosang;
156  if (gPad) {
157  xx *= pixeltoX;
158  yy *= pixeltoY;
159  }
160  xv[i] = xx + fX1;
161  yv[i] = yy + fY1;
162  }
163  if (gPad) gPad->Modified();
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Compute distance from point px,py to a line.
168 
169 Int_t TCurlyLine::DistancetoPrimitive(Int_t px, Int_t py)
170 {
171  return DistancetoLine(px,py,fX1,fY1,fX2,fY2);
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// Execute action corresponding to one event.
176 ///
177 /// This member function is called when a TCurlyLine is clicked with the locator
178 ///
179 /// If Left button clicked on one of the line end points, this point
180 /// follows the cursor until button is released.
181 ///
182 /// if Middle button clicked, the line is moved parallel to itself
183 /// until the button is released.
184 
185 void TCurlyLine::ExecuteEvent(Int_t event, Int_t px, Int_t py)
186 {
187  if (!gPad) return;
188 
189  Int_t kMaxDiff = 20;
190  static Int_t d1,d2,px1,px2,py1,py2;
191  static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
192  static Bool_t p1, p2, pL;
193  Int_t dx, dy;
194 
195  Bool_t opaque = gPad->OpaqueMoving();
196 
197  switch (event) {
198 
199  case kArrowKeyPress:
200  case kButton1Down:
201  if (!opaque) {
202  gVirtualX->SetLineColor(-1);
203  TAttLine::Modify(); //Change line attributes only if necessary
204  }
205 
206  // No break !!!
207 
208  case kMouseMotion:
209 
210  px1 = gPad->XtoAbsPixel(fX1);
211  py1 = gPad->YtoAbsPixel(fY1);
212  px2 = gPad->XtoAbsPixel(fX2);
213  py2 = gPad->YtoAbsPixel(fY2);
214 
215  p1 = p2 = pL = kFALSE;
216 
217  d1 = TMath::Abs(px1 - px) + TMath::Abs(py1-py); //simply take sum of pixels differences
218  if (d1 < kMaxDiff) { //*-*================>OK take point number 1
219  px1old = px1; py1old = py1;
220  p1 = kTRUE;
221  gPad->SetCursor(kPointer);
222  return;
223  }
224  d2 = TMath::Abs(px2 - px) + TMath::Abs(py2-py); //simply take sum of pixels differences
225  if (d2 < kMaxDiff) { //*-*================>OK take point number 2
226  px2old = px2; py2old = py2;
227  p2 = kTRUE;
228  gPad->SetCursor(kPointer);
229  return;
230  }
231 
232  pL = kTRUE;
233  pxold = px; pyold = py;
234  gPad->SetCursor(kMove);
235 
236  break;
237 
238  case kArrowKeyRelease:
239  case kButton1Motion:
240 
241  if (p1) {
242  if (!opaque) {
243  gVirtualX->DrawLine(px1old, py1old, px2, py2);
244  gVirtualX->DrawLine(px, py, px2, py2);
245  }
246  else this->SetStartPoint(gPad->AbsPixeltoX(px),gPad->AbsPixeltoY(py));
247  px1old = px;
248  py1old = py;
249  }
250  if (p2) {
251  if (!opaque) {
252  gVirtualX->DrawLine(px1, py1, px2old, py2old);
253  gVirtualX->DrawLine(px1, py1, px, py);
254  }
255  else this->SetEndPoint(gPad->AbsPixeltoX(px), gPad->AbsPixeltoY(py));
256  px2old = px;
257  py2old = py;
258  }
259  if (pL) {
260  if (!opaque) gVirtualX->DrawLine(px1, py1, px2, py2);
261  dx = px-pxold; dy = py-pyold;
262  px1 += dx; py1 += dy; px2 += dx; py2 += dy;
263  if (!opaque) gVirtualX->DrawLine(px1, py1, px2, py2);
264  pxold = px;
265  pyold = py;
266  if (opaque) {
267  this->SetStartPoint(gPad->AbsPixeltoX(px1),gPad->AbsPixeltoY(py1));
268  this->SetEndPoint(gPad->AbsPixeltoX(px2), gPad->AbsPixeltoY(py2));
269  }
270  }
271 
272  if (opaque) {
273  if (p1) {
274  //check in which corner the BBox is edited
275  if (fX1>fX2) {
276  if (fY1>fY2)
277  gPad->ShowGuidelines(this, event, '2', true);
278  else
279  gPad->ShowGuidelines(this, event, '3', true);
280  }
281  else {
282  if (fY1>fY2)
283  gPad->ShowGuidelines(this, event, '1', true);
284  else
285  gPad->ShowGuidelines(this, event, '4', true);
286  }
287  }
288  if (p2) {
289  //check in which corner the BBox is edited
290  if (fX1>fX2) {
291  if (fY1>fY2)
292  gPad->ShowGuidelines(this, event, '4', true);
293  else
294  gPad->ShowGuidelines(this, event, '1', true);
295  }
296  else {
297  if (fY1>fY2)
298  gPad->ShowGuidelines(this, event, '3', true);
299  else
300  gPad->ShowGuidelines(this, event, '2', true);
301  }
302  }
303  if (pL) {
304  gPad->ShowGuidelines(this, event, 'i', true);
305  }
306  gPad->Modified(kTRUE);
307  gPad->Update();
308  }
309  break;
310 
311  case kButton1Up:
312 
313  if (opaque) {
314  gPad->ShowGuidelines(this, event);
315  } else {
316  if (p1) {
317  fX1 = gPad->AbsPixeltoX(px);
318  fY1 = gPad->AbsPixeltoY(py);
319  }
320  if (p2) {
321  fX2 = gPad->AbsPixeltoX(px);
322  fY2 = gPad->AbsPixeltoY(py);
323  }
324  if (pL) {
325  fX1 = gPad->AbsPixeltoX(px1);
326  fY1 = gPad->AbsPixeltoY(py1);
327  fX2 = gPad->AbsPixeltoX(px2);
328  fY2 = gPad->AbsPixeltoY(py2);
329  }
330  }
331  Build();
332  gPad->Modified();
333  if (!opaque) gVirtualX->SetLineColor(-1);
334  }
335 }
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Save primitive as a C++ statement(s) on output stream out
339 
340 void TCurlyLine::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
341 {
342  if (gROOT->ClassSaved(TCurlyLine::Class())) {
343  out<<" ";
344  } else {
345  out<<" TCurlyLine *";
346  }
347  out<<"curlyline = new TCurlyLine("
348  <<fX1<<","<<fY1<<","<<fX2<<","<<fY2<<","
349  <<fWaveLength<<","<<fAmplitude<<");"<<std::endl;
350  if (!fIsCurly) {
351  out<<" curlyline->SetWavy();"<<std::endl;
352  }
353  SaveLineAttributes(out,"curlyline",1,1,1);
354  out<<" curlyline->Draw();"<<std::endl;
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Set curly.
359 
360 void TCurlyLine::SetCurly()
361 {
362  fIsCurly = kTRUE;
363  Build();
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Set wavy.
368 
369 void TCurlyLine::SetWavy()
370 {
371  fIsCurly = kFALSE;
372  Build();
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Set wave length.
377 
378 void TCurlyLine::SetWaveLength(Double_t x)
379 {
380  fWaveLength = x;
381  Build();
382 }
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// Set amplitude.
386 
387 void TCurlyLine::SetAmplitude(Double_t x)
388 {
389  fAmplitude = x;
390  Build();
391 }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// Set start point.
395 
396 void TCurlyLine::SetStartPoint(Double_t x, Double_t y)
397 {
398  fX1 = x;
399  fY1 = y;
400  Build();
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// Set end point.
405 
406 void TCurlyLine::SetEndPoint(Double_t x, Double_t y)
407 {
408  fX2 = x;
409  fY2 = y;
410  Build();
411 }
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Set default wave length.
415 
416 void TCurlyLine::SetDefaultWaveLength(Double_t WaveLength)
417 {
418  fgDefaultWaveLength = WaveLength;
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
422 /// Set default amplitude.
423 
424 void TCurlyLine::SetDefaultAmplitude(Double_t Amplitude)
425 {
426  fgDefaultAmplitude = Amplitude;
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 /// Set default "IsCurly".
431 
432 void TCurlyLine::SetDefaultIsCurly(Bool_t IsCurly)
433 {
434  fgDefaultIsCurly = IsCurly;
435 }
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Get default wave length.
439 
440 Double_t TCurlyLine::GetDefaultWaveLength()
441 {
442  return fgDefaultWaveLength;
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Get default amplitude.
447 
448 Double_t TCurlyLine::GetDefaultAmplitude()
449 {
450  return fgDefaultAmplitude;
451 }
452 
453 ////////////////////////////////////////////////////////////////////////////////
454 /// Get default "IsCurly".
455 
456 Bool_t TCurlyLine::GetDefaultIsCurly()
457 {
458  return fgDefaultIsCurly;
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Return the bounding Box of the CurlyLine
463 
464 Rectangle_t TCurlyLine::GetBBox()
465 {
466  Rectangle_t BBox;
467  Int_t px1, py1, px2, py2;
468  px1 = gPad->XtoPixel(fX1);
469  px2 = gPad->XtoPixel(fX2);
470  py1 = gPad->YtoPixel(fY1);
471  py2 = gPad->YtoPixel(fY2);
472 
473  Int_t tmp;
474  if (px1>px2) { tmp = px1; px1 = px2; px2 = tmp;}
475  if (py1>py2) { tmp = py1; py1 = py2; py2 = tmp;}
476 
477  BBox.fX = px1;
478  BBox.fY = py1;
479  BBox.fWidth = px2-px1;
480  BBox.fHeight = py2-py1;
481 
482  return (BBox);
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// Return the center of the BoundingBox as TPoint in pixels
487 
488 TPoint TCurlyLine::GetBBoxCenter()
489 {
490  TPoint p;
491  p.SetX(gPad->XtoPixel(TMath::Min(fX1,fX2)+0.5*(TMath::Max(fX1, fX2)-TMath::Min(fX1, fX2))));
492  p.SetY(gPad->YtoPixel(TMath::Min(fY1,fY2)+0.5*(TMath::Max(fY1, fY2)-TMath::Min(fY1, fY2))));
493  return(p);
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Set center of the BoundingBox
498 
499 void TCurlyLine::SetBBoxCenter(const TPoint &p)
500 {
501  Double_t w = TMath::Max(fX1, fX2)-TMath::Min(fX1, fX2);
502  Double_t h = TMath::Max(fY1, fY2)-TMath::Min(fY1, fY2);
503  Double_t x1, x2, y1, y2;
504  x1 = x2 = y1 = y2 = 0;
505 
506  if (fX2>fX1) {
507  x1 = gPad->PixeltoX(p.GetX())-0.5*w;
508  x2 = gPad->PixeltoX(p.GetX())+0.5*w;
509  }
510  else {
511  x2 = gPad->PixeltoX(p.GetX())-0.5*w;
512  x1 = gPad->PixeltoX(p.GetX())+0.5*w;
513  }
514  if (fY2>fY1) {
515  y1 = gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0))-0.5*h;
516  y2 = gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0))+0.5*h;
517  }
518  else {
519  y2 = gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0))-0.5*h;
520  y1 = gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0))+0.5*h;
521  }
522  this->SetStartPoint(x1, y1);
523  this->SetEndPoint(x2, y2);
524 }
525 
526 ////////////////////////////////////////////////////////////////////////////////
527 /// Set X coordinate of the center of the BoundingBox
528 
529 void TCurlyLine::SetBBoxCenterX(const Int_t x)
530 {
531  Double_t w = TMath::Max(fX1, fX2)-TMath::Min(fX1, fX2);
532  if (fX2>fX1) {
533  this->SetStartPoint(gPad->PixeltoX(x)-0.5*w, fY1);
534  this->SetEndPoint(gPad->PixeltoX(x)+0.5*w, fY2);
535  }
536  else {
537  this->SetEndPoint(gPad->PixeltoX(x)-0.5*w, fY2);
538  this->SetStartPoint(gPad->PixeltoX(x)+0.5*w, fY1);
539  }
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 /// Set Y coordinate of the center of the BoundingBox
544 
545 void TCurlyLine::SetBBoxCenterY(const Int_t y)
546 {
547  Double_t h = TMath::Max(fY1, fY2)-TMath::Min(fY1, fY2);
548  if (fY2>fY1) {
549  this->SetStartPoint(fX1, gPad->PixeltoY(y-gPad->VtoPixel(0))-0.5*h);
550  this->SetEndPoint(fX2, gPad->PixeltoY(y-gPad->VtoPixel(0))+0.5*h);
551  }
552  else {
553  this->SetEndPoint(fX2, gPad->PixeltoY(y-gPad->VtoPixel(0))-0.5*h);
554  this->SetStartPoint(fX1, gPad->PixeltoY(y-gPad->VtoPixel(0))+0.5*h);
555  }
556 }
557 
558 ////////////////////////////////////////////////////////////////////////////////
559 /// Set left hand side of BoundingBox to a value
560 /// (resize in x direction on left)
561 
562 void TCurlyLine::SetBBoxX1(const Int_t x)
563 {
564  if (fX2>fX1)
565  this->SetStartPoint(gPad->PixeltoX(x), fY1);
566  else
567  this->SetEndPoint(gPad->PixeltoX(x), fY2);
568 }
569 
570 ////////////////////////////////////////////////////////////////////////////////
571 /// Set right hands ide of BoundingBox to a value
572 /// (resize in x direction on right)
573 
574 void TCurlyLine::SetBBoxX2(const Int_t x)
575 {
576  if (fX2>fX1)
577  this->SetEndPoint(gPad->PixeltoX(x), fY2);
578  else
579  this->SetStartPoint(gPad->PixeltoX(x), fY1);
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
583 /// Set top of BoundingBox to a value (resize in y direction on top)
584 
585 void TCurlyLine::SetBBoxY1(const Int_t y)
586 {
587  if (fY2>fY1)
588  this->SetEndPoint(fX2, gPad->PixeltoY(y - gPad->VtoPixel(0)));
589  else
590  this->SetStartPoint(fX1, gPad->PixeltoY(y - gPad->VtoPixel(0)));
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 /// Set bottom of BoundingBox to a value
595 /// (resize in y direction on bottom)
596 
597 void TCurlyLine::SetBBoxY2(const Int_t y)
598 {
599  if (fY2>fY1)
600  this->SetStartPoint(fX1, gPad->PixeltoY(y - gPad->VtoPixel(0)));
601  else
602  this->SetEndPoint(fX2, gPad->PixeltoY(y - gPad->VtoPixel(0)));
603 }