Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TArrow.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Rene Brun 17/10/95
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 #include "Riostream.h"
13 #include "TROOT.h"
14 #include "TMath.h"
15 #include "TArrow.h"
16 #include "TVirtualPad.h"
17 #include "TVirtualPS.h"
18 
19 Float_t TArrow::fgDefaultAngle = 60;
20 Float_t TArrow::fgDefaultArrowSize = 0.05;
21 TString TArrow::fgDefaultOption = ">";
22 
23 ClassImp(TArrow);
24 
25 /** \class TArrow
26 \ingroup BasicGraphics
27 
28 Draw all kinds of Arrows.
29 
30 The different arrow's formats are explained in TArrow::TArrow.
31 The picture below gives some examples.
32 
33 Once an arrow is drawn on the screen:
34 
35 - One can click on one of the edges and move this edge.
36 - One can click on any other arrow part to move the entire arrow.
37 
38 Begin_Macro(source)
39 ../../../tutorials/graphics/arrows.C
40 End_Macro
41 */
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Arrow default constructor.
45 
46 TArrow::TArrow(): TLine(),TAttFill()
47 {
48  fAngle = fgDefaultAngle;
49  fArrowSize = 0.;
50 }
51 
52 ////////////////////////////////////////////////////////////////////////////////
53 /// Arrow normal constructor.
54 ///
55 /// Define an arrow between points x1,y1 and x2,y2
56 /// the `arrowsize` is in percentage of the pad height
57 /// Opening angle between the two sides of the arrow is fAngle (60 degrees)
58 /// ~~~ {.cpp}
59 /// option = ">" -------->
60 /// option = "|->" |------->
61 /// option = "<" <--------
62 /// option = "<-|" <-------|
63 /// option = "->-" ---->----
64 /// option = "-<-" ----<----
65 /// option = "-|>-" ---|>----
66 /// option = "<>" <------->
67 /// option = "<|>" <|-----|> arrow defined by a triangle
68 /// ~~~
69 /// Note:
70 ///
71 /// - If FillColor == 0 an open triangle is drawn, otherwise a full triangle is
72 /// drawn with the fill color. The default is filled with LineColor
73 /// - The "Begin" and "end" bars options can be combined with any other options.
74 /// - The 9 options described above cannot be mixed.
75 
76 TArrow::TArrow(Double_t x1, Double_t y1,Double_t x2, Double_t y2,
77  Float_t arrowsize ,Option_t *option)
78  :TLine(x1,y1,x2,y2), TAttFill(0,1001)
79 {
80 
81  fAngle = fgDefaultAngle;
82  fArrowSize = arrowsize;
83  fOption = option;
84  SetFillColor(GetLineColor());
85 }
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 /// Arrow default destructor.
89 
90 TArrow::~TArrow()
91 {
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 /// Copy constructor.
96 
97 TArrow::TArrow(const TArrow &arrow) : TLine(), TAttFill()
98 {
99  fAngle = fgDefaultAngle;
100  fArrowSize = 0.;
101  arrow.Copy(*this);
102 }
103 
104 ////////////////////////////////////////////////////////////////////////////////
105 /// Copy this arrow to arrow
106 
107 void TArrow::Copy(TObject &obj) const
108 {
109  TLine::Copy(obj);
110  TAttFill::Copy(((TArrow&)obj));
111  ((TArrow&)obj).fAngle = fAngle;
112  ((TArrow&)obj).fArrowSize = fArrowSize;
113  ((TArrow&)obj).fOption = fOption;
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Draw this arrow with its current attributes.
118 
119 void TArrow::Draw(Option_t *option)
120 {
121  Option_t *opt;
122  if (option && strlen(option)) opt = option;
123  else opt = (char*)GetOption();
124 
125  AppendPad(opt);
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Draw this arrow with new coordinates.
130 ///
131 /// - if `arrowsize` is <= 0, `arrowsize` will be the current arrow size
132 /// - if `option=""`, `option` will be the current arrow option
133 
134 void TArrow::DrawArrow(Double_t x1, Double_t y1,Double_t x2, Double_t y2,
135  Float_t arrowsize ,Option_t *option)
136 {
137 
138  Float_t size = arrowsize;
139  if (size <= 0) size = fArrowSize;
140  if (size <= 0) size = 0.05;
141  const char* opt = option;
142  if (!opt || !opt[0]) opt = fOption.Data();
143  if (!opt || !opt[0]) opt = "|>";
144  TArrow *newarrow = new TArrow(x1,y1,x2,y2,size,opt);
145  newarrow->SetAngle(fAngle);
146  TAttLine::Copy(*newarrow);
147  TAttFill::Copy(*newarrow);
148  newarrow->SetBit(kCanDelete);
149  newarrow->AppendPad(opt);
150 }
151 
152 ////////////////////////////////////////////////////////////////////////////////
153 /// Paint this arrow with its current attributes.
154 
155 void TArrow::Paint(Option_t *option)
156 {
157  Option_t *opt;
158  if (option && strlen(option)) opt = option;
159  else opt = (char*)GetOption();
160  if (TestBit(kLineNDC))
161  PaintArrow(gPad->GetX1() + fX1 * (gPad->GetX2() - gPad->GetX1()),
162  gPad->GetY1() + fY1 * (gPad->GetY2() - gPad->GetY1()),
163  gPad->GetX1() + fX2 * (gPad->GetX2() - gPad->GetX1()),
164  gPad->GetY1() + fY2 * (gPad->GetY2() - gPad->GetY1()), fArrowSize, opt);
165  else
166  PaintArrow(gPad->XtoPad(fX1), gPad->YtoPad(fY1), gPad->XtoPad(fX2), gPad->YtoPad(fY2), fArrowSize, opt);
167 }
168 
169 ////////////////////////////////////////////////////////////////////////////////
170 /// Draw this arrow
171 
172 void TArrow::PaintArrow(Double_t x1, Double_t y1, Double_t x2, Double_t y2,
173  Float_t arrowsize, Option_t *option)
174 {
175 
176  // Option and attributes
177  TString opt = option;
178  opt.ToLower();
179  TAttLine::Modify();
180  TAttFill::Modify();
181 
182  // Compute the gPad coordinates in TRUE normalized space (NDC)
183  Int_t iw = gPad->GetWw();
184  Int_t ih = gPad->GetWh();
185  Double_t x1p,y1p,x2p,y2p;
186  gPad->GetPadPar(x1p,y1p,x2p,y2p);
187  Int_t ix1 = (Int_t)(iw*x1p);
188  Int_t iy1 = (Int_t)(ih*y1p);
189  Int_t ix2 = (Int_t)(iw*x2p);
190  Int_t iy2 = (Int_t)(ih*y2p);
191  Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
192  Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
193  Double_t rh = hndc/(Double_t)ih;
194  Double_t rw = wndc/(Double_t)iw;
195  Double_t x1ndc = (Double_t)ix1*rw;
196  Double_t y1ndc = (Double_t)iy1*rh;
197  Double_t x2ndc = (Double_t)ix2*rw;
198  Double_t y2ndc = (Double_t)iy2*rh;
199 
200  // Ratios to convert user space in TRUE normalized space (NDC)
201  Double_t rx1,ry1,rx2,ry2;
202  gPad->GetRange(rx1,ry1,rx2,ry2);
203  Double_t rx = (x2ndc-x1ndc)/(rx2-rx1);
204  Double_t ry = (y2ndc-y1ndc)/(ry2-ry1);
205 
206  // Arrow position and arrow's middle in NDC space
207  Double_t x1n = rx*(x1-rx1)+x1ndc;
208  Double_t x2n = rx*(x2-rx1)+x1ndc;
209  Double_t y1n = ry*(y1-ry1)+y1ndc;
210  Double_t y2n = ry*(y2-ry1)+y1ndc;
211  Double_t xm = (x1n+x2n)/2;
212  Double_t ym = (y1n+y2n)/2;
213 
214  // Arrow heads size
215  Double_t length = TMath::Sqrt(Double_t((x2n-x1n)*(x2n-x1n)+(y2n-y1n)*(y2n-y1n)));
216  Double_t rSize = 0.7*arrowsize;
217  Double_t dSize = rSize*TMath::Tan(TMath::Pi()*fAngle/360);
218  Double_t cosT = (length > 0) ? (x2n-x1n)/length : 1.;
219  Double_t sinT = (length > 0) ? (y2n-y1n)/length : 0.;
220 
221  // Draw the start and end bars if needed
222  if (opt.BeginsWith("|-")) {
223  Double_t x1ar[2], y1ar[2];
224  x1ar[0] = x1n-sinT*dSize;
225  y1ar[0] = y1n+cosT*dSize;
226  x1ar[1] = x1n+sinT*dSize;
227  y1ar[1] = y1n-cosT*dSize;
228  // NDC to user coordinates
229  for (Int_t i=0; i<2; i++) {
230  x1ar[i] = (1/rx)*(x1ar[i]-x1ndc)+rx1;
231  y1ar[i] = (1/ry)*(y1ar[i]-y1ndc)+ry1;
232  }
233  gPad->PaintLine(x1ar[0],y1ar[0],x1ar[1],y1ar[1]);
234  opt(0) = ' ';
235  }
236  if (opt.EndsWith("-|")) {
237  Double_t x2ar[2], y2ar[2];
238  x2ar[0] = x2n-sinT*dSize;
239  y2ar[0] = y2n+cosT*dSize;
240  x2ar[1] = x2n+sinT*dSize;
241  y2ar[1] = y2n-cosT*dSize;
242  // NDC to user coordinates
243  for (Int_t i=0; i<2; i++) {
244  x2ar[i] = (1/rx)*(x2ar[i]-x1ndc)+rx1;
245  y2ar[i] = (1/ry)*(y2ar[i]-y1ndc)+ry1;
246  }
247  gPad->PaintLine(x2ar[0],y2ar[0],x2ar[1],y2ar[1]);
248  opt(opt.Length()-1) = ' ';
249  }
250 
251  // Move arrow head's position if needed
252  Double_t x1h = x1n;
253  Double_t y1h = y1n;
254  Double_t x2h = x2n;
255  Double_t y2h = y2n;
256  if (opt.Contains("->-") || opt.Contains("-|>-")) {
257  x2h = xm + cosT*rSize/2;
258  y2h = ym + sinT*rSize/2;
259  }
260  if (opt.Contains("-<-") || opt.Contains("-<|-")) {
261  x1h = xm - cosT*rSize/2;
262  y1h = ym - sinT*rSize/2;
263  }
264 
265  // Paint Arrow body
266  if (opt.Contains("|>") && !opt.Contains("-|>-")) {
267  x2n -= cosT*rSize;
268  y2n -= sinT*rSize;
269  }
270  if (opt.Contains("<|") && !opt.Contains("-<|-")) {
271  x1n += cosT*rSize;
272  y1n += sinT*rSize;
273  }
274  x1n = (1/rx)*(x1n-x1ndc)+rx1;
275  y1n = (1/ry)*(y1n-y1ndc)+ry1;
276  x2n = (1/rx)*(x2n-x1ndc)+rx1;
277  y2n = (1/ry)*(y2n-y1ndc)+ry1;
278  gPad->PaintLine(x1n,y1n,x2n,y2n);
279 
280  // Draw the arrow's head(s)
281  if (opt.Contains(">")) {
282  Double_t x2ar[4], y2ar[4];
283 
284  x2ar[0] = x2h - rSize*cosT - sinT*dSize;
285  y2ar[0] = y2h - rSize*sinT + cosT*dSize;
286  x2ar[1] = x2h;
287  y2ar[1] = y2h;
288  x2ar[2] = x2h - rSize*cosT + sinT*dSize;
289  y2ar[2] = y2h - rSize*sinT - cosT*dSize;
290  x2ar[3] = x2ar[0];
291  y2ar[3] = y2ar[0];
292 
293  // NDC to user coordinates
294  for (Int_t i=0; i<4; i++) {
295  x2ar[i] = (1/rx)*(x2ar[i]-x1ndc)+rx1;
296  y2ar[i] = (1/ry)*(y2ar[i]-y1ndc)+ry1;
297  }
298  if (opt.Contains("|>")) {
299  if (gVirtualX) gVirtualX->SetLineStyle(1);
300  if (gVirtualPS) gVirtualPS->SetLineStyle(1);
301  if (GetFillColor()) {
302  gPad->PaintFillArea(3,x2ar,y2ar);
303  gPad->PaintPolyLine(4,x2ar,y2ar);
304  } else {
305  gPad->PaintPolyLine(4,x2ar,y2ar);
306  }
307  } else {
308  gPad->PaintPolyLine(3,x2ar,y2ar);
309  }
310  }
311 
312  if (opt.Contains("<")) {
313  Double_t x1ar[4], y1ar[4];
314  x1ar[0] = x1h + rSize*cosT + sinT*dSize;
315  y1ar[0] = y1h + rSize*sinT - cosT*dSize;
316  x1ar[1] = x1h;
317  y1ar[1] = y1h;
318  x1ar[2] = x1h + rSize*cosT - sinT*dSize;
319  y1ar[2] = y1h + rSize*sinT + cosT*dSize;
320  x1ar[3] = x1ar[0];
321  y1ar[3] = y1ar[0];
322 
323  // NDC to user coordinates
324  for (Int_t i=0; i<4; i++) {
325  x1ar[i] = (1/rx)*(x1ar[i]-x1ndc)+rx1;
326  y1ar[i] = (1/ry)*(y1ar[i]-y1ndc)+ry1;
327  }
328  if (opt.Contains("<|")) {
329  if (gVirtualX) gVirtualX->SetLineStyle(1);
330  if (gVirtualPS) gVirtualPS->SetLineStyle(1);
331  if (GetFillColor()) {
332  gPad->PaintFillArea(3,x1ar,y1ar);
333  gPad->PaintPolyLine(4,x1ar,y1ar);
334  } else {
335  gPad->PaintPolyLine(4,x1ar,y1ar);
336  }
337  } else {
338  gPad->PaintPolyLine(3,x1ar,y1ar);
339  }
340  }
341 }
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 /// Save primitive as a C++ statement(s) on output stream out
345 
346 void TArrow::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
347 {
348 
349  char quote = '"';
350  if (gROOT->ClassSaved(TArrow::Class())) {
351  out<<" ";
352  } else {
353  out<<" TArrow *";
354  }
355  out<<"arrow = new TArrow("<<fX1<<","<<fY1<<","<<fX2<<","<<fY2
356  <<","<<fArrowSize<<","<<quote<<GetDrawOption()<<quote<<");"<<std::endl;
357 
358  SaveFillAttributes(out,"arrow",0,1);
359  SaveLineAttributes(out,"arrow",1,1,1);
360 
361  if (TestBit(kLineNDC))
362  out<<" arrow->SetNDC();"<<std::endl;
363 
364  if (fAngle!=60)
365  out << " arrow->SetAngle(" << GetAngle() << ");" << std::endl;
366 
367  out<<" arrow->Draw();"<<std::endl;
368 }
369 
370 
371 ////////////////////////////////////////////////////////////////////////////////
372 /// Set default angle.
373 
374 void TArrow::SetDefaultAngle(Float_t Angle)
375 {
376  fgDefaultAngle = Angle;
377 }
378 
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Set default arrow sive.
382 
383 void TArrow::SetDefaultArrowSize (Float_t ArrowSize)
384 {
385  fgDefaultArrowSize = ArrowSize;
386 }
387 
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// Set default option.
391 
392 void TArrow::SetDefaultOption(Option_t *Option)
393 {
394 
395  fgDefaultOption = Option;
396 }
397 
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Get default angle.
401 
402 Float_t TArrow::GetDefaultAngle()
403 {
404 
405  return fgDefaultAngle;
406 }
407 
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Get default arrow size.
411 
412 Float_t TArrow::GetDefaultArrowSize()
413 {
414 
415  return fgDefaultArrowSize;
416 }
417 
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 /// Get default option.
421 
422 Option_t *TArrow::GetDefaultOption()
423 {
424 
425  return fgDefaultOption.Data();
426 }