Logo ROOT   master
Reference Guide
TLatex.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Nicolas Brun, Olivier Couet, Oleksandr Grebenyuk
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 "TLatex.h"
15 #include "TMathText.h"
16 #include "TMath.h"
17 #include "TVirtualPad.h"
18 #include "TVirtualPS.h"
19 #include "TVirtualX.h"
20 
22 
24 
25 /** \class TLatex
26 \ingroup BasicGraphics
27 
28 To draw Mathematical Formula.
29 
30 TLatex's purpose is to write mathematical equations. The syntax is very similar
31 to the Latex's one. It provides several functionalities:
32 
33 - [Subscripts and Superscripts](#L1)
34 - [Fractions](#L2)
35 - [Splitting Lines](#L3)
36 - [Roots](#L4)
37 - [Mathematical Symbols](#L5)
38 - [Delimiters](#L6)
39 - [Greek Letters](#L7)
40 - [Accents](#L8)
41 - [Changing Style](#L9)
42 - [Alignment Rules](#L10)
43 - [Character Adjustment](#L11)
44 - [Italic and Boldface](#L12)
45 - [Examples](#L13)
46 - [Interface to TMathText](#L14)
47 
48 When the font precision (see `TAttText`) is low (0 or 1), TLatex is
49 painted as a normal TText, the control characters are not interpreted.
50 
51 ## <a name="L1"></a> Subscripts and Superscripts
52 Subscripts and superscripts are made with the `_` and `^`
53 commands. These commands can be combined to make complicated subscript and
54 superscript expressions. You may adjust the display of subscripts and
55 superscripts by using the two functions `SetIndiceSize(Double_t)`,
56 which set relative size of subscripts and superscripts, and
57 `SetLimitIndiceSize(Int_t)`, which set limits for text resizing of
58 subscripts and superscripts.
59 
60 Examples:
61 
62 Begin_Macro
63 {
64  TCanvas *cl = new TCanvas("cl","cl",10,10,700,500);
65  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
66  Double_t dy = 1./7.;
67  Tl.DrawText(.1, dy, "x^{2y} :"); Tl.DrawLatex(.5, dy, "x^{2y}");
68  Tl.DrawText(.1, 2*dy, "x_{2y} :"); Tl.DrawLatex(.5, 2*dy, "x_{2y}");
69  Tl.DrawText(.1, 3*dy, "x^{y^{2}} :"); Tl.DrawLatex(.5, 3*dy, "x^{y^{2}}");
70  Tl.DrawText(.1, 4*dy, "x^{y_{1}} :"); Tl.DrawLatex(.5, 4*dy, "x^{y_{1}}");
71  Tl.DrawText(.1, 5*dy, "x^{y}_{1} :"); Tl.DrawLatex(.5, 5*dy, "x^{y}_{1}");
72  Tl.DrawText(.1, 6*dy, "x_{1}^{y} :"); Tl.DrawLatex(.5, 6*dy, "x_{1}^{y}");
73 }
74 End_Macro
75 
76 The best way to put the subscripts and superscripts before the character and not
77 after, is to use an empty character:
78 
79 Begin_Macro
80 {
81  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
82  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
83  Tl.DrawText(.1, .5, "{}^{40}_{20}Ca :"); Tl.DrawLatex(.5, .5, "{}^{40}_{20}Ca");
84 }
85 End_Macro
86 
87 The subscripts and superscripts operators apply not only on one character but
88 on all the "normal text" preceding them. In the following example the second
89 `E` is lower than the first one because the operator `_` is
90 applied on `/f` which has a descending part, and not only on `f`
91 which as no descending part.
92 
93 Begin_Macro
94 {
95  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
96  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
97  Tl.DrawText(.1, .5, "f_{E}/f_{E} :"); Tl.DrawLatex(.5, .5, "f_{E}/f_{E}");
98 }
99 End_Macro
100 
101 To make sure the second operator `_` applies only on `f` a dummy operator `^{}`
102 should be introduced to separate the `f` from the `/`.
103 
104 Begin_Macro
105 {
106  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
107  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
108  Tl.DrawText(.1, .5, "f_{E}/^{}f_{E} :"); Tl.DrawLatex(.5, .5, "f_{E}/^{}f_{E}");
109 }
110 End_Macro
111 
112 ## <a name="L2"></a> Fractions
113 Fractions denoted by the `/` symbol are made in the obvious way.
114 The `#frac` command is used for large fractions in displayed formula;
115 it has two arguments: the numerator and the denominator.
116 
117 Examples:
118 
119 Begin_Macro
120 {
121  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
122  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
123  Tl.DrawText(.1, .5, "x = #frac{y+z/2}{y^{2}+1} :"); Tl.DrawLatex(.5, .5, "x = #frac{y+z/2}{y^{2}+1}");
124 }
125 End_Macro
126 
127 ## <a name="L3"></a> Splitting Lines
128 Text can be split in two lines via the command `#splitline`.
129 
130 Examples:
131 
132 Begin_Macro
133 {
134  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
135  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
136  Tl.DrawText(.1, .5, "#splitline{21 April 2003}{14:02:30} :"); Tl.DrawLatex(.6, .5, "#splitline{21 April 2003}{14:02:30}");
137 }
138 End_Macro
139 
140 ## <a name="L4"></a> Roots
141 The `#sqrt` command produces the square root of its argument; it has
142 an optional first argument for other roots.
143 
144 Examples:
145 
146 Begin_Macro
147 {
148  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
149  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
150  Tl.DrawText(.1, .5, "#sqrt{10} #sqrt[3]{10} :"); Tl.DrawLatex(.5, .5, "#sqrt{10} #sqrt[3]{10}");
151 }
152 End_Macro
153 
154 ## <a name="L5"></a> Mathematical Symbols
155 TLatex can display dozens of special mathematical symbols. A few of them, such
156 as `+` and `>` , are produced by typing the corresponding
157 keyboard character. Others are obtained with the commands in the following
158 table:
159 
160 Begin_Macro
161 mathsymbols.C
162 End_Macro
163 
164 
165 ## <a name="L6"></a> Delimiters
166 TLatex provides 4 kinds of proportional delimiters:
167 
168  #[]{....} or "a la" Latex #left[.....#right] : big square brackets
169  #{}{....} or #left{.....#right} : big curly brackets
170  #||{....} or #left|.....#right| : big absolute value symbols
171  #(){....} or #left(.....#right) : big parentheses
172 
173 ## <a name="L7"></a> Greek Letters
174 The command to produce a lowercase Greek letter is obtained by adding a
175 `#` to the name of the letter. For an uppercase Greek letter, just
176 capitalize the first letter of the command name. Some letters have two
177 representations. The name of the second one (the "variation") starts with "var".
178 The following table gives the complete list:
179 
180 Begin_Macro
181 greekletters.C
182 End_Macro
183 
184 
185 ## <a name="L8"></a> Accents
186 Several kind of accents are available:
187 
188 Begin_Macro
189 {
190  TCanvas *cl = new TCanvas("cl","cl",10,10,700,300);
191  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
192  Tl.DrawText(.1, .10, "#hat : "); Tl.DrawLatex(.3, .10, " #hat{a} ");
193  Tl.DrawText(.1, .23, "#check : "); Tl.DrawLatex(.3, .23, " #check{a} ");
194  Tl.DrawText(.1, .36, "#acute : "); Tl.DrawLatex(.3, .36, " #acute{a} ");
195  Tl.DrawText(.1, .50, "#grave : "); Tl.DrawLatex(.3, .50, " #grave{a} ");
196  Tl.DrawText(.1, .63, "#dot : "); Tl.DrawLatex(.3, .63, " #dot{a} ");
197  Tl.DrawText(.1, .76, "#ddot : "); Tl.DrawLatex(.3, .76, " #ddot{a} ");
198  Tl.DrawText(.1, .90, "#tilde : "); Tl.DrawLatex(.3, .90, " #tilde{a} ");
199 }
200 End_Macro
201 
202 
203 The special sign: `#slash` draws a slash on top of the text between brackets:
204 
205 Begin_Macro
206 {
207  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
208  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
209  Tl.DrawText(.1, .5, "#slash{E}_{T} :"); Tl.DrawLatex(.5, .5, "#slash{E}_{T}");
210 }
211 End_Macro
212 
213 Bar and vectors sign are done the following way:
214 
215 Begin_Macro
216 {
217  TCanvas *cl = new TCanvas("cl","cl",10,10,700,100);
218  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
219  Tl.DrawText(.1, .5, "#bar{a} and #vec{a} :"); Tl.DrawLatex(.5, .5, "#bar{a} and #vec{a}");
220 }
221 End_Macro
222 
223 ## <a name="L9"></a> Changing Style
224 One can change the font, the text color, or the text size at any time using :
225 `#font[font-number]{...}`, `#color[color-number]{...}`
226 and `#scale[scale-factor]{...}`
227 
228 Examples:
229 
230 Begin_Macro
231 {
232  TCanvas *cl = new TCanvas("cl","cl",10,10,900,300);
233  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
234  Double_t dy = 1./4.;
235  Tl.DrawText(.01, dy, "#font[12]{Times Italic} and #font[22]{Times bold} :"); Tl.DrawLatex(.7, dy, "#font[12]{Times Italic} and #font[22]{Times bold}");
236  Tl.DrawText(.01, 2*dy, "#color[2]{Red} and #color[4]{Blue} :"); Tl.DrawLatex(.7, 2*dy, "#color[2]{Red} and #color[4]{Blue}");
237  Tl.DrawText(.01, 3*dy, "#scale[1.2]{Bigger} and #scale[0.8]{Smaller} :"); Tl.DrawLatex(.7, 3*dy, "#scale[1.2]{Bigger} and #scale[0.8]{Smaller}");
238 }
239 End_Macro
240 
241 ## <a name="L10"></a> Alignment Rules
242 The `TText` alignment rules apply to the `TLatex` objects with one exception
243 concerning the vertical alignment:
244 
245 - if the vertical alignment = 1 , subscripts are not taken into account
246 - if the vertical alignment = 0 , the text is aligned to the box surrounding
247  the full text with sub and superscripts
248 
249 This is illustrated by the following example:
250 
251 Begin_Macro(source)
252 {
253  TCanvas Tlva("Tlva","Tlva",500,500);
254  Tlva.SetGrid();
255  Tlva.DrawFrame(0,0,1,1);
256  const char *longstring = "K_{S}... K^{*0}... #frac{2s}{#pi#alpha^{2}} #frac{d#sigma}{dcos#theta} (e^{+}e^{-} #rightarrow f#bar{f} ) = #left| #frac{1}{1 - #Delta#alpha} #right|^{2} (1+cos^{2}#theta)";
257 
258  TLatex latex;
259  latex.SetTextSize(0.025);
260  latex.SetTextAlign(13); //align at top
261  latex.DrawLatex(.2,.9,"K_{S}");
262  latex.DrawLatex(.3,.9,"K^{*0}");
263  latex.DrawLatex(.2,.8,longstring);
264 
265  latex.SetTextAlign(12); //centered
266  latex.DrawLatex(.2,.6,"K_{S}");
267  latex.DrawLatex(.3,.6,"K^{*0}");
268  latex.DrawLatex(.2,.5,longstring);
269 
270  latex.SetTextAlign(11); //default bottom alignment
271  latex.DrawLatex(.2,.4,"K_{S}");
272  latex.DrawLatex(.3,.4,"K^{*0}");
273  latex.DrawLatex(.2,.3,longstring);
274 
275  latex.SetTextAlign(10); //special bottom alignment
276  latex.DrawLatex(.2,.2,"K_{S}");
277  latex.DrawLatex(.3,.2,"K^{*0}");
278  latex.DrawLatex(.2,.1,longstring);
279 
280  latex.SetTextAlign(12);
281  latex.SetTextFont(72);
282  latex.DrawLatex(.1,.80,"13");
283  latex.DrawLatex(.1,.55,"12");
284  latex.DrawLatex(.1,.35,"11");
285  latex.DrawLatex(.1,.18,"10");
286  return Tlva;
287 }
288 End_Macro
289 
290 
291 ## <a name="L11"></a> Character Adjustment
292 
293 The two commands `#kern` and `#lower` enable a better control
294 over character placement. The command `#kern[(Float_t)dx]{text}` moves
295 the output string horizontally by the fraction `dx` of its length.
296 Similarly, `#lower[(Float_t)dy]{text}` shifts the text up or down by
297 the fraction `dy` of its height.
298 
299 Examples:
300 
301 Begin_Macro
302 {
303  TCanvas *cl = new TCanvas("cl","cl",10,10,900,300);
304  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
305  TLatex Tt; Tt.SetTextFont(43); Tt.SetTextSize(16);
306  Double_t dy = 1./7.;
307  Tl.DrawLatex(.5, dy, "Positive k#kern[0.3]{e}#kern[0.3]{r}#kern[0.3]{n}#kern[0.3]{i}#kern[0.3]{n}#kern[0.3]{g}");
308  Tt.DrawText(.01, 2*dy, "Positive k#kern[0.3]{e}#kern[0.3]{r}#kern[0.3]{n}#kern[0.3]{i}#kern[0.3]{n}#kern[0.3]{g} :");
309  Tl.DrawLatex(.5, 3*dy, "Negative k#kern[-0.3]{e}#kern[-0.3]{r}#kern[-0.3]{n}#kern[-0.3]{i}#kern[-0.3]{n}#kern[-0.3]{g}");
310  Tt.DrawText(.01, 4*dy, "Negative k#kern[-0.3]{e}#kern[-0.3]{r}#kern[-0.3]{n}#kern[-0.3]{i}#kern[-0.3]{n}#kern[-0.3]{g} :");
311  Tl.DrawLatex(.5, 5*dy, "Vertical a#lower[0.2]{d}#lower[0.4]{j}#lower[0.1]{u}#lower[-0.1]{s}#lower[-0.3]{t}#lower[-0.4]{m}#lower[-0.2]{e}#lower[0.1]{n}t");
312  Tt.DrawText(.01, 6*dy, "Vertical a#lower[0.2]{d}#lower[0.4]{j}#lower[0.1]{u}#lower[-0.1]{s}#lower[-0.3]{t}#lower[-0.4]{m}#lower[-0.2]{e}#lower[0.1]{n}t :");
313 
314 }
315 End_Macro
316 
317 ## <a name="L12"></a> Italic and Boldface
318 Text can be turned italic or boldface using the commands
319 `#it` and `#bf`.
320 
321 Examples:
322 
323 Begin_Macro
324 {
325  TCanvas *cl = new TCanvas("cl","cl",10,10,900,300);
326  TLatex Tl; Tl.SetTextFont(43); Tl.SetTextSize(20);
327  Double_t dy = 1./3.;
328  Tl.DrawText(.01, dy, "abc#alpha#beta#gamma, #it{abc#alpha#beta#gamma} :"); Tl.DrawLatex(.7, dy, "abc#alpha#beta#gamma, #it{abc#alpha#beta#gamma}");
329  Tl.DrawText(.01, 2*dy, "#bf{bold}, #it{italic}, #bf{#it{bold italic}}, #bf{#bf{unbold}} :"); Tl.DrawLatex(.7, 2*dy, "#bf{bold}, #it{italic}, #bf{#it{bold italic}}, #bf{#bf{unbold}}");
330 }
331 End_Macro
332 
333 ## <a name="L13"></a> Examples
334 
335 Begin_Macro(source)
336 {
337  TCanvas ex1("ex1","Latex",500,600);
338  TLatex Tl;
339  Tl.SetTextAlign(12);
340  Tl.SetTextSize(0.04);
341  Tl.DrawLatex(0.1,0.8,"1) C(x) = d #sqrt{#frac{2}{#lambdaD}} #int^{x}_{0}cos(#frac{#pi}{2}t^{2})dt");
342  Tl.DrawLatex(0.1,0.6,"2) C(x) = d #sqrt{#frac{2}{#lambdaD}} #int^{x}cos(#frac{#pi}{2}t^{2})dt");
343  Tl.DrawLatex(0.1,0.4,"3) R = |A|^{2} = #frac{1}{2}(#[]{#frac{1}{2}+C(V)}^{2}+#[]{#frac{1}{2}+S(V)}^{2})");
344  Tl.DrawLatex(0.1,0.2,"4) F(t) = #sum_{i=-#infty}^{#infty}A(i)cos#[]{#frac{i}{t+i}}");
345  return ex1;
346 }
347 End_Macro
348 Begin_Macro(source)
349 {
350  TCanvas ex2("ex2","Latex",500,300);
351  TLatex Tl;
352  Tl.SetTextAlign(23);
353  Tl.SetTextSize(0.08);
354  Tl.DrawLatex(0.5,0.95,"e^{+}e^{-}#rightarrowZ^{0}#rightarrowI#bar{I}, q#bar{q}");
355  Tl.DrawLatex(0.5,0.75,"|#vec{a}#bullet#vec{b}|=#Sigmaa^{i}_{jk}+b^{bj}_{i}");
356  Tl.DrawLatex(0.5,0.5,"i(#partial_{#mu}#bar{#psi}#gamma^{#mu}+m#bar{#psi}=0#Leftrightarrow(#Box+m^{2})#psi=0");
357  Tl.DrawLatex(0.5,0.3,"L_{em}=eJ^{#mu}_{em}A_{#mu} , J^{#mu}_{em}=#bar{I}#gamma_{#mu}I , M^{j}_{i}=#SigmaA_{#alpha}#tau^{#alphaj}_{i}");
358  return ex2;
359 }
360 End_Macro
361 Begin_Macro(source)
362 {
363  TCanvas ex3("ex3","Latex",500,300);
364  TPaveText pt(.1,.1,.9,.9);
365  pt.AddText("#frac{2s}{#pi#alpha^{2}} #frac{d#sigma}{dcos#theta} (e^{+}e^{-} #rightarrow f#bar{f} ) = ");
366  pt.AddText("#left| #frac{1}{1 - #Delta#alpha} #right|^{2} (1+cos^{2}#theta");
367  pt.AddText("+ 4 Re #left{ #frac{2}{1 - #Delta#alpha} #chi(s) #[]{#hat{g}_{#nu}^{e}#hat{g}_{#nu}^{f} (1 + cos^{2}#theta) + 2 #hat{g}_{a}^{e}#hat{g}_{a}^{f} cos#theta) } #right}");
368  pt.SetLabel("Born equation");
369  pt.Draw();
370  return ex3;
371 }
372 End_Macro
373 
374 
375 ## <a name="L14"></a> Interface to TMathText
376 
377 The class `TMathText` is a TeX math formulae interpreter. It uses plain
378 TeX syntax and uses "\" as control instead of "#". If a piece of text containing
379 "\" is given to `TLatex` then `TMathText` is automatically invoked.
380 Therefore, as histograms' titles, axis titles, labels etc ... are drawn using
381 `TLatex`, the `TMathText` syntax can be used for them also.
382 */
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// Default constructor.
386 
388 {
389  fFactorSize = 1.5;
390  fFactorPos = 0.6;
391  fError = 0;
392  fShow = kFALSE;
393  fPos = 0;
394  fTabMax = 0;
395  fOriginSize = 0.04;
396  fTabSize = 0;
397  fItalic = kFALSE;
398  fLimitFactorSize = 3;
399  SetLineWidth(2);
400 }
401 
402 ////////////////////////////////////////////////////////////////////////////////
403 /// Normal constructor.
404 
405 TLatex::TLatex(Double_t x, Double_t y, const char *text)
406  :TText(x,y,text)
407 {
408  fFactorSize = 1.5;
409  fFactorPos = 0.6;
410  fError = 0;
411  fShow = kFALSE;
412  fPos = 0;
413  fTabMax = 0;
414  fOriginSize = 0.04;
415  fTabSize = 0;
416  fItalic = kFALSE;
417  fLimitFactorSize = 3;
418  SetLineWidth(2);
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
422 /// Destructor.
423 
425 {
426 }
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// Copy constructor.
430 
432 {
433  fFactorSize = 1.5;
434  fFactorPos = 0.6;
435  fError = 0;
436  fShow = kFALSE;
437  fPos = 0;
438  fTabMax = 0;
439  fOriginSize = 0.04;
440  fTabSize = 0;
441  fItalic = kFALSE;
442  fLimitFactorSize = 3;
443  ((TLatex&)text).Copy(*this);
444 }
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 ///assignment operator
448 
449 TLatex& TLatex::operator=(const TLatex& lt)
450 {
451  if(this!=&lt) {
452  TText::operator=(lt);
457  fError=lt.fError;
458  fShow=lt.fShow;
459  fTabSize=lt.fTabSize;
461  fTabSize=lt.fTabSize;
462  fTabSize=lt.fTabSize;
463  fItalic=lt.fItalic;
464  }
465  return *this;
466 }
467 
468 ////////////////////////////////////////////////////////////////////////////////
469 /// Copy this TLatex object to another TLatex.
470 
471 void TLatex::Copy(TObject &obj) const
472 {
473  ((TLatex&)obj).fFactorSize = fFactorSize;
474  ((TLatex&)obj).fFactorPos = fFactorPos;
475  ((TLatex&)obj).fLimitFactorSize = fLimitFactorSize;
476  ((TLatex&)obj).fError = fError;
477  ((TLatex&)obj).fShow = fShow;
478  ((TLatex&)obj).fTabSize = 0;
479  ((TLatex&)obj).fOriginSize = fOriginSize;
480  ((TLatex&)obj).fTabMax = fTabMax;
481  ((TLatex&)obj).fPos = fPos;
482  ((TLatex&)obj).fItalic = fItalic;
483  TText::Copy(obj);
484  TAttLine::Copy(((TAttLine&)obj));
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Analyse function.
489 
491 {
492  return Analyse(0,0,spec,t,length);
493 }
494 
495 ////////////////////////////////////////////////////////////////////////////////
496 /// Analyse and paint the TLatex formula
497 ///
498 /// It is called twice : first for calculating the size of
499 /// each portion of the formula, then to paint the formula.
500 /// When analyse finds an operator or separator, it calls
501 /// itself recursively to analyse the arguments of the operator.
502 /// when the argument is an atom (normal text), it calculates
503 /// the size of it and return it as the result.
504 /// for example : if the operator #frac{arg1}{arg2} is found :
505 /// Analyse(arg1) return the size of arg1 (width, up, down)
506 /// Analyse(arg2) return the size of arg2
507 /// now, we know the size of #frac{arg1}{arg2}:
508 ///
509 /// ~~~ {.cpp}
510 /// width = max(width_arg1, width_arg2)
511 /// up = up_arg1 + down_arg1
512 /// down = up_arg2 + down_arg2
513 /// ~~~
514 ///
515 /// so, when the user wants to paint a fraction at position (x,y),
516 /// the rect used for the formula is : (x,y-up,x+width,y+down)
517 ///
518 /// return size of zone occupied by the text/formula
519 /// - `t` : chain to be analyzed
520 /// - `length` : number of chars in t.
521 
523 {
524  const char *tab[] = { "alpha","beta","chi","delta","varepsilon","phi","gamma","eta","iota","varphi","kappa","lambda",
525  "mu","nu","omicron","pi","theta","rho","sigma","tau","upsilon","varomega","omega","xi","psi","zeta",
526  "Alpha","Beta","Chi","Delta","Epsilon","Phi","Gamma","Eta","Iota","vartheta",
527  "Kappa","Lambda","Mu","Nu","Omicron","Pi","Theta","Rho","Sigma","Tau",
528  "Upsilon","varsigma","Omega","Xi","Psi","Zeta","varUpsilon","epsilon"};
529 
530  const char *tab2[] = { "leq","/","infty","voidb","club","diamond","heart",
531  "spade","leftrightarrow","leftarrow","uparrow","rightarrow",
532  "downarrow","circ","pm","doublequote","geq","times","propto",
533  "partial","bullet","divide","neq","equiv","approx","3dots",
534  "cbar","topbar","downleftarrow","aleph","Jgothic","Rgothic","voidn",
535  "otimes","oplus","oslash","cap","cup","supset","supseteq",
536  "notsubset","subset","subseteq","in","notin","angle","nabla",
537  "oright","ocopyright","trademark","prod","surd","upoint","corner","wedge",
538  "vee","Leftrightarrow","Leftarrow","Uparrow","Rightarrow",
539  "Downarrow","diamond","LT","void1","copyright","void3","sum",
540  "arctop","lbar","arcbottom","topbar","void8", "bottombar","arcbar",
541  "ltbar","AA","aa","void06","GT","int","forall","exists" };
542 
543  const char *tab3[] = { "bar","vec","dot","hat","ddot","acute","grave","check","tilde","slash"};
544 
545  if (fError != 0) return TLatexFormSize(0,0,0);
546 
547  Int_t nBlancDeb=0,nBlancFin=0,l_nBlancDeb=0,l_nBlancFin=0;
548  Int_t i,k;
549  Int_t min=0, max=0;
550  Bool_t cont = kTRUE;
551  while(cont) {
552  // count leading blanks
553  //while(nBlancDeb+nBlancFin<length && t[nBlancDeb]==' ') nBlancDeb++;
554 
555  if (nBlancDeb==length) return TLatexFormSize(0,0,0); // empty string
556 
557  // count trailing blanks
558  //while(nBlancDeb+nBlancFin<length && t[length-nBlancFin-1]==' ') nBlancFin++;
559 
560  if (nBlancDeb==l_nBlancDeb && nBlancFin==l_nBlancFin) cont = kFALSE;
561 
562  // remove characters { }
563  if (t[nBlancDeb]=='{' && t[length-nBlancFin-1]=='}') {
564  Int_t nBrackets = 0;
565  Bool_t sameBrackets = kTRUE;
566  for(i=nBlancDeb;i<length-nBlancFin;i++) {
567  if (t[i] == '{' && !(i>0 && t[i-1] == '@')) nBrackets++;
568  if (t[i] == '}' && t[i-1]!= '@') nBrackets--;
569  if (nBrackets==0 && i<length-nBlancFin-2) {
570  sameBrackets=kFALSE;
571  break;
572  }
573  }
574 
575  if (sameBrackets) {
576  // begin and end brackets match
577  nBlancDeb++;
578  nBlancFin++;
579  if (nBlancDeb+nBlancFin==length) return TLatexFormSize(0,0,0); // empty string
580  cont = kTRUE;
581  }
582 
583  }
584 
585  l_nBlancDeb = nBlancDeb;
586  l_nBlancFin = nBlancFin;
587  }
588 
589  // make a copy of the current processed chain of characters
590  // removing leading and trailing blanks
591  length -= nBlancFin+nBlancDeb; // length of string without blanks
592  if (length <=0) {
593  Error("Analyse", "It seems there is a syntax error in the TLatex string");
594  return TLatexFormSize(0,0,0);
595  }
596  Char_t* text = new Char_t[length+1];
597  strncpy(text,t+nBlancDeb,length);
598  text[length] = 0;
599 
600  // compute size of subscripts and superscripts
601  Double_t indiceSize = spec.fSize/fFactorSize;
603  indiceSize = spec.fSize;
604  // subtract 0.001 because of rounding errors
605  TextSpec_t specNewSize = spec;
606  specNewSize.fSize = indiceSize;
607 
608  // recherche des operateurs
609  Int_t opPower = -1; // Position of first ^ (power)
610  Int_t opUnder = -1; // Position of first _ (indice)
611  Int_t opFrac = -1; // Position of first \frac
612  Int_t opSqrt = -1; // Position of first \sqrt
613  Int_t nBrackets = 0; // Nesting level in { }
614  Int_t nCroch = 0; // Nesting level in [ ]
615  Int_t opCurlyCurly = -1; // Position of first }{
616  Int_t opSquareCurly = -1; // Position of first ]{
617  Int_t opCloseCurly = -2; // Position of first }
618  Int_t opColor = -1; // Position of first #color
619  Int_t opFont = -1; // Position of first #font
620  Int_t opScale = -1; // Position of first #scale
621  Int_t opGreek = -1; // Position of a Greek letter
622  Int_t opSpec = -1; // position of a special character
623  Int_t opAbove = -1; // position of a vector/overline
624  Int_t opSquareBracket = 0 ; // position of a "[]{" operator (#[]{arg})
625  Int_t opBigCurly = 0 ; // position of a "{}{" operator (big curly bracket #{}{arg})
626  Int_t opAbs = 0 ; // position of a "||{" operator (absolute value) (#||{arg})
627  Int_t opParen = 0 ; // position of a "(){" operator (big parenthesis #(){arg})
628  Int_t abovePlace = 0 ; // true if subscripts must be written above and not after
629  Int_t opBox = 0 ; // position of #Box
630  Int_t opPerp = 0; // position of #perp
631  Int_t opOdot = 0; // position of #odot
632  Int_t opHbar = 0; // position of #hbar
633  Int_t opMinus = 0; // position of #minus
634  Int_t opPlus = 0; // position of #plus
635  Int_t opMp = 0; // position of #mp
636  Int_t opBackslash = 0; // position of #backslash
637  Int_t opParallel = 0; // position of #parallel
638  Int_t opSplitLine = -1; // Position of first #splitline
639  Int_t opKern = -1; // Position of first #kern
640  Int_t opLower = -1; // Position of first #lower
641  Int_t opBf = -1; // Position of first #bf
642  Int_t opIt = -1; // Position of first #it
643  Int_t opMbox = -1; // Position of first #mbox
644 
645  Bool_t opFound = kFALSE;
646  Bool_t quote1 = kFALSE, quote2 = kFALSE ;
647 
648  for(i=0;i<length;i++) {
649  switch (text[i]) {
650  case '\'' : quote1 = !quote1 ; break ;
651  case '"' : quote2 = !quote2 ; break ;
652  }
653  //if (quote1 || quote2) continue ;
654  switch (text[i]) {
655  case '{':
656  if (nCroch==0) {
657  if (!(i>0 && text[i-1] == '@')) nBrackets++;
658  }
659  break;
660  case '}':
661  if (nCroch==0) {
662  if (!(i>0 && text[i-1] == '@')) nBrackets--;
663  if (nBrackets==0) {
664  if (i<length-1) if (text[i+1]=='{' && opCurlyCurly==-1) opCurlyCurly=i;
665  if (i<length-2) {
666  if (text[i+1]!='{' && !(text[i+2]=='{' && (text[i+1]=='^' || text[i+1]=='_'))
667  && opCloseCurly==-2) opCloseCurly=i;
668  }
669  else if (i<length-1) {
670  if (text[i+1]!='{' && opCloseCurly==-2) opCloseCurly=i;
671  }
672  else if (opCloseCurly==-2) opCloseCurly=i;
673  }
674  }
675  break;
676  case '[':
677  if (nBrackets==0) {
678  if (!(i>0 && text[i-1] == '@')) nCroch++;
679  }
680  break;
681  case ']':
682  if (nBrackets==0) {
683  if (!(i>0 && text[i-1] == '@')) nCroch--;
684  if (nCroch<0) {
685  // more "]" than "["
686  fError = "Missing \"[\"";
687  delete [] text;
688  return TLatexFormSize(0,0,0);
689  }
690  }
691  break;
692  }
693  if (length>i+1) {
694  Char_t buf[3];
695  strncpy(buf,&text[i],2);
696  if (strncmp(buf,"^{",2)==0) {
697  if (opPower==-1 && nBrackets==0 && nCroch==0) opPower=i;
698  if (i>3) {
699  Char_t buf1[5];
700  strncpy(buf1,&text[i-4],4);
701  if (strncmp(buf1,"#int",4)==0) {
702  abovePlace = 1;
703  if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
704  }
705  if (strncmp(buf1,"#sum",4)==0) {
706  abovePlace = 2;
707  if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
708  }
709  }
710  }
711  if (strncmp(buf,"_{",2)==0) {
712  if (opUnder==-1 && nBrackets==0 && nCroch==0) opUnder=i;
713  if (i>3) {
714  Char_t buf2[5];
715  strncpy(buf2,&text[i-4],4);
716  if (strncmp(buf2,"#int",4)==0) {
717  abovePlace = 1;
718  if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
719  }
720  if (strncmp(buf2,"#sum",4)==0) {
721  abovePlace = 2;
722  if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
723  }
724  }
725  }
726  if (strncmp(buf,"]{",2)==0)
727  if (opSquareCurly==-1 && nBrackets==0 && nCroch==0) opSquareCurly=i;
728  }
729  // detect other operators
730  if (text[i]=='\\' || (text[i]=='#' && !opFound && nBrackets==0 && nCroch==0)) {
731 
732  if (length>i+10) {
733  Char_t buf[11];
734  strncpy(buf,&text[i+1],10);
735  if (strncmp(buf,"splitline{",10)==0) {
736  opSplitLine=i; opFound = kTRUE;
737  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
738  continue;
739  }
740  }
741  if (length>i+9) {
742  Char_t buf[10];
743  strncpy(buf,&text[i+1],9);
744  if (!opBackslash && strncmp(buf,"backslash",9)==0) {
745  opBackslash=1; opFound = kTRUE;
746  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
747  continue;
748  }
749  }
750  if (length>i+8) {
751  Char_t buf[9];
752  strncpy(buf,&text[i+1],8);
753  if (!opParallel && strncmp(buf,"parallel",8)==0) {
754  opParallel=1; opFound = kTRUE;
755  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
756  continue;
757  }
758  }
759  if (length>i+6) {
760  Char_t buf[7];
761  strncpy(buf,&text[i+1],6);
762  if (strncmp(buf,"lower[",6)==0 || strncmp(buf,"lower{",6)==0) {
763  opLower=i; opFound = kTRUE;
764  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
765  continue ;
766  }
767  if (strncmp(buf,"scale[",6)==0 || strncmp(buf,"scale{",6)==0) {
768  opScale=i; opFound = kTRUE;
769  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
770  continue ;
771  }
772  if (strncmp(buf,"color[",6)==0 || strncmp(buf,"color{",6)==0) {
773  opColor=i; opFound = kTRUE;
774  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
775  continue ;
776  }
777  }
778  if (length>i+5) {
779  Char_t buf[6];
780  strncpy(buf,&text[i+1],5);
781  if (strncmp(buf,"frac{",5)==0) {
782  opFrac=i; opFound = kTRUE;
783  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
784  continue;
785  }
786  if (strncmp(buf,"sqrt{",5)==0 || strncmp(buf,"sqrt[",5)==0) {
787  opSqrt=i; opFound = kTRUE;
788  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
789  continue;
790  }
791  if (strncmp(buf,"font{",5)==0 || strncmp(buf,"font[",5)==0) {
792  opFont=i; opFound = kTRUE;
793  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
794  continue;
795  }
796  if (strncmp(buf,"kern[",5)==0 || strncmp(buf,"kern{",5)==0) {
797  opKern=i; opFound = kTRUE;
798  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
799  continue ;
800  }
801  if (!opMinus && strncmp(buf,"minus",5)==0) {
802  opMinus=1; opFound = kTRUE;
803  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
804  continue;
805  }
806  if (strncmp(buf,"mbox[",5)==0 || strncmp(buf,"mbox{",5)==0) {
807  opMbox=i; opFound = kTRUE;
808  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
809  continue ;
810  }
811  }
812  if (length>i+4) {
813  Char_t buf[5];
814  strncpy(buf,&text[i+1],4);
815  if (!opOdot && strncmp(buf,"odot",4)==0) {
816  opOdot=1; opFound = kTRUE;
817  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
818  continue;
819  }
820  if (!opHbar && strncmp(buf,"hbar",4)==0) {
821  opHbar=1; opFound = kTRUE;
822  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
823  continue;
824  }
825  if (!opPerp && strncmp(buf,"perp",4)==0) {
826  opPerp=1; opFound = kTRUE;
827  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
828  continue;
829  }
830  if (!opPlus && strncmp(buf,"plus",4)==0) {
831  opPlus=1; opFound = kTRUE;
832  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
833  continue;
834  }
835  }
836  if (length>i+3) {
837  Char_t buf[4];
838  strncpy(buf,&text[i+1],3);
839  buf[3] = 0;
840  if (strncmp(buf,"[]{",3)==0) {
841  opSquareBracket=1; opFound = kTRUE;
842  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
843  continue;
844  }
845  if (strncmp(buf,"{}{",3)==0 ) {
846  opBigCurly=1; opFound = kTRUE;
847  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
848  continue;
849  }
850  if (strncmp(buf,"||{",3)==0) {
851  opAbs=1; opFound = kTRUE;
852  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
853  continue;
854  }
855  if (strncmp(buf,"(){",3)==0) {
856  opParen=1; opFound = kTRUE;
857  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
858  continue;
859  }
860  if (!opBox && strncmp(buf,"Box",3)==0) {
861  opBox=1; opFound = kTRUE;
862  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
863  continue;
864  }
865  if (strncmp(buf,"bf[",3)==0 || strncmp(buf,"bf{",3)==0) {
866  opBf=i; opFound = kTRUE;
867  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
868  continue ;
869  }
870  if (strncmp(buf,"it[",3)==0 || strncmp(buf,"it{",3)==0) {
871  opIt=i; opFound = kTRUE;
872  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
873  continue ;
874  }
875  }
876  if (length>i+2) {
877  Char_t buf[3];
878  strncpy(buf,&text[i+1],2);
879  if (!opMp && strncmp(buf,"mp",2)==0) {
880  opMp=1; opFound = kTRUE;
881  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
882  continue;
883  }
884  }
885  for(k=0;k<54;k++) {
886  if (!opFound && UInt_t(length)>i+strlen(tab[k])) {
887  if (strncmp(&text[i+1],tab[k],strlen(tab[k]))==0) {
888  opGreek=k;
889  opFound = kTRUE;
890  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
891  }
892  }
893  }
894  for(k=0;k<10;k++) {
895  if (!opFound && UInt_t(length)>i+strlen(tab3[k])) {
896  if (strncmp(&text[i+1],tab3[k],strlen(tab3[k]))==0) {
897  opAbove=k;
898  opFound = kTRUE;
899  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
900  }
901  }
902  }
903  UInt_t lastsize = 0;
904  if (!opFound)
905  for(k=0;k<82;k++) {
906  if ((opSpec==-1 || strlen(tab2[k])>lastsize) && UInt_t(length)>i+strlen(tab2[k])) {
907  if (strncmp(&text[i+1],tab2[k],strlen(tab2[k]))==0) {
908  lastsize = strlen(tab2[k]);
909  opSpec=k;
910  opFound = kTRUE;
911  if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
912  }
913  }
914  }
915  }
916  }
917 
918  TLatexFormSize fs1;
919  TLatexFormSize fs2;
920  TLatexFormSize fs3;
921  TLatexFormSize result;
922 
923  // analysis of operators found
924  if (opCloseCurly>-1 && opCloseCurly<length-1) { // separator } found
925  if(!fShow) {
926  fs1 = Anal1(spec,text,opCloseCurly+1);
927  fs2 = Anal1(spec,text+opCloseCurly+1,length-opCloseCurly-1);
928  Savefs(&fs1);
929  } else {
930  fs1 = Readfs();
931  Analyse(x+fs1.Width(),y,spec,text+opCloseCurly+1,length-opCloseCurly-1);
932  Analyse(x,y,spec,text,opCloseCurly+1);
933  }
934  result = fs1+fs2;
935  }
936 
937  else if (opPower>-1 && opUnder>-1) { // ^ and _ found
938  min = TMath::Min(opPower,opUnder);
939  max = TMath::Max(opPower,opUnder);
940  Double_t xfpos = 0. ; //GetHeight()*spec.fSize/5.;
941  Double_t prop=1, propU=1; // scale factor for #sum & #int
942  switch (abovePlace) {
943  case 1 :
944  prop = .8 ; propU = 1.75 ; // Int
945  break;
946  case 2:
947  prop = .9 ; propU = 1.75 ; // Sum
948  break;
949  }
950  // propU acts on upper number
951  // when increasing propU value, the upper indice position is higher
952  // when increasing prop values, the lower indice position is lower
953 
954  if (!fShow) {
955  Int_t ltext = min ;
956  if (min >= 2 && strncmp(&text[min-2],"{}",2)==0) {
957  // upper and lower indice before the character
958  // like with chemical element
959  snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
960  ltext-- ;
961  }
962  fs1 = Anal1(spec,text,ltext);
963  fs2 = Anal1(specNewSize,text+min+1,max-min-1);
964  fs3 = Anal1(specNewSize,text+max+1,length-max-1);
965  Savefs(&fs1);
966  Savefs(&fs2);
967  Savefs(&fs3);
968  } else {
969  fs3 = Readfs();
970  fs2 = Readfs();
971  fs1 = Readfs();
972  Double_t pos = 0;
973  if (!abovePlace) {
974  Double_t addW = fs1.Width()+xfpos, addH1, addH2;
975  if (opPower<opUnder) {
976  addH1 = -fs1.Over()*(fFactorPos)-fs2.Under();
977  addH2 = fs1.Under()+fs3.Over()*(fFactorPos);
978  } else {
979  addH1 = fs1.Under()+fs2.Over()*(fFactorPos);
980  addH2 = -fs1.Over()*(fFactorPos)-fs3.Under();
981  }
982  Analyse(x+addW,y+addH2,specNewSize,text+max+1,length-max-1);
983  Analyse(x+addW,y+addH1,specNewSize,text+min+1,max-min-1);
984  } else {
985  Double_t addW1, addW2, addH1, addH2;
986  Double_t m = TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width()));
987  pos = (m-fs1.Width())/2;
988  if (opPower<opUnder) {
989  addH1 = -fs1.Over()*propU-fs2.Under();
990  addW1 = (m-fs2.Width())/2;
991  addH2 = fs1.Under()*prop+fs3.Over();
992  addW2 = (m-fs3.Width())/2;
993  } else {
994  addH1 = fs1.Under()*prop+fs2.Over();
995  addW1 = (m-fs2.Width())/2;
996  addH2 = -fs1.Over()*propU-fs3.Under();
997  addW2 = (m-fs3.Width())/2;
998  }
999 
1000  Analyse(x+addW2,y+addH2,specNewSize,text+max+1,length-max-1);
1001  Analyse(x+addW1,y+addH1,specNewSize,text+min+1,max-min-1);
1002  }
1003 
1004  if (min >= 2 && strncmp(&text[min-2],"{}",2)==0) {
1005  snprintf(&text[min-2],length-(min-2)," ") ;
1006  Analyse(x+pos,y,spec,text,min-1);
1007  } else {
1008  Analyse(x+pos,y,spec,text,min);
1009  }
1010  }
1011 
1012  if (!abovePlace) {
1013  if (opPower<opUnder) {
1014  result.Set(fs1.Width()+xfpos+TMath::Max(fs2.Width(),fs3.Width()),
1015  fs1.Over()*fFactorPos+fs2.Height(),
1016  fs1.Under()+fs3.Height()-fs3.Over()*(1-fFactorPos));
1017  } else {
1018  result.Set(fs1.Width()+xfpos+TMath::Max(fs2.Width(),fs3.Width()),
1019  fs1.Over()*fFactorPos+fs3.Height(),
1020  fs1.Under()+fs2.Height()-fs2.Over()*(1-fFactorPos));
1021  }
1022  } else {
1023  if (opPower<opUnder) {
1024  result.Set(TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width())),
1025  fs1.Over()*propU+fs2.Height(),fs1.Under()*prop+fs3.Height());
1026  } else {
1027  result.Set(TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width())),
1028  fs1.Over()*propU+fs3.Height(),fs1.Under()*prop+fs2.Height());
1029  }
1030  }
1031  }
1032  else if (opPower>-1) { // ^ found
1033  Double_t prop=1;
1034  Double_t xfpos = 0. ; //GetHeight()*spec.fSize/5. ;
1035  switch (abovePlace) {
1036  case 1 : //int
1037  prop = 1.75 ; break ;
1038  case 2 : // sum
1039  prop = 1.75; break ;
1040  }
1041  // When increasing prop, the upper indice position is higher
1042  if (!fShow) {
1043  Int_t ltext = opPower ;
1044  if (ltext >= 2 && strncmp(&text[ltext-2],"{}",2)==0) {
1045  // upper and lower indice before the character
1046  // like with chemical element
1047  snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
1048  ltext-- ;
1049  }
1050  fs1 = Anal1(spec,text,ltext);
1051  fs2 = Anal1(specNewSize,text+opPower+1,length-opPower-1);
1052  Savefs(&fs1);
1053  Savefs(&fs2);
1054  } else {
1055  fs2 = Readfs();
1056  fs1 = Readfs();
1057  Int_t pos = 0;
1058  if (!abovePlace){
1059  Double_t over = fs1.Over();
1060  if (over <= 0) over = 1.5*fs2.Over();
1061  Analyse(x+fs1.Width()+xfpos,y-over*fFactorPos-fs2.Under(),specNewSize,text+opPower+1,length-opPower-1);
1062  } else {
1063  Int_t pos2=0;
1064  if (fs2.Width()>fs1.Width())
1065  pos=Int_t((fs2.Width()-fs1.Width())/2);
1066  else
1067  pos2=Int_t((fs1.Width()-fs2.Width())/2);
1068 
1069  Analyse(x+pos2,y-fs1.Over()*prop-fs2.Under(),specNewSize,text+opPower+1,length-opPower-1);
1070  }
1071  if (opPower >= 2 && strncmp(&text[opPower-2],"{}",2)==0) {
1072  snprintf(&text[opPower-2],length-(opPower-2)," ") ;
1073  Analyse(x+pos,y,spec,text,opPower-1);
1074  } else {
1075  Analyse(x+pos,y,spec,text,opPower);
1076  }
1077  }
1078 
1079  if (!abovePlace)
1080  result.Set(fs1.Width()+xfpos+fs2.Width(),
1081  fs1.Over()*fFactorPos+fs2.Over(),fs1.Under());
1082  else
1083  result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Over()*prop+fs2.Height(),fs1.Under());
1084 
1085  }
1086  else if (opUnder>-1) { // _ found
1087  Double_t prop = .9; // scale factor for #sum & #frac
1088  Double_t xfpos = 0.;//GetHeight()*spec.fSize/5. ;
1089  Double_t fpos = fFactorPos ;
1090  // When increasing prop, the lower indice position is lower
1091  if(!fShow) {
1092  Int_t ltext = opUnder ;
1093  if (ltext >= 2 && strncmp(&text[ltext-2],"{}",2)==0) {
1094  // upper and lower indice before the character
1095  // like with chemical element
1096  snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
1097  ltext-- ;
1098  }
1099  fs1 = Anal1(spec,text,ltext);
1100  fs2 = Anal1(specNewSize,text+opUnder+1,length-opUnder-1);
1101  Savefs(&fs1);
1102  Savefs(&fs2);
1103  } else {
1104  fs2 = Readfs();
1105  fs1 = Readfs();
1106  Int_t pos = 0;
1107  if (!abovePlace)
1108  Analyse(x+fs1.Width()+xfpos,y+fs1.Under()+fs2.Over()*fpos,specNewSize,text+opUnder+1,length-opUnder-1);
1109  else {
1110  Int_t pos2=0;
1111  if (fs2.Width()>fs1.Width())
1112  pos=Int_t((fs2.Width()-fs1.Width())/2);
1113  else
1114  pos2=Int_t((fs1.Width()-fs2.Width())/2);
1115 
1116  Analyse(x+pos2,y+fs1.Under()*prop+fs2.Over(),specNewSize,text+opUnder+1,length-opUnder-1);
1117  }
1118  if (opUnder >= 2 && strncmp(&text[opUnder-2],"{}",2)==0) {
1119  snprintf(&text[opUnder-2],length-(opUnder-2)," ") ;
1120  Analyse(x+pos,y,spec,text,opUnder-1);
1121  } else {
1122  Analyse(x+pos,y,spec,text,opUnder);
1123  }
1124  }
1125  if (!abovePlace)
1126  result.Set(fs1.Width()+xfpos+fs2.Width(),fs1.Over(),
1127  fs1.Under()+fs2.Under()+fs2.Over()*fpos);
1128  else
1129  result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Over(),fs1.Under()*prop+fs2.Height());
1130  }
1131  else if (opBox) {
1132  Double_t square = GetHeight()*spec.fSize/2;
1133  if (!fShow) {
1134  fs1 = Anal1(spec,text+4,length-4);
1135  } else {
1136  fs1 = Analyse(x+square,y,spec,text+4,length-4);
1137  Double_t adjust = GetHeight()*spec.fSize/20;
1138  Double_t x1 = x+adjust ;
1139  Double_t x2 = x-adjust+square ;
1140  Double_t y1 = y;
1141  Double_t y2 = y-square+adjust;
1142  DrawLine(x1,y1,x2,y1,spec);
1143  DrawLine(x2,y1,x2,y2,spec);
1144  DrawLine(x2,y2,x1,y2,spec);
1145  DrawLine(x1,y2,x1,y1,spec);
1146  }
1147  result = fs1 + TLatexFormSize(square,square,0);
1148  }
1149  else if (opOdot) {
1150  Double_t square = GetHeight()*spec.fSize/2;
1151  if (!fShow) {
1152  fs1 = Anal1(spec,text+5,length-5);
1153  } else {
1154  fs1 = Analyse(x+1.3*square,y,spec,text+5,length-5);
1155  Double_t adjust = GetHeight()*spec.fSize/20;
1156  Double_t r1 = 0.62*square;
1157  Double_t y1 = y-0.3*square-adjust;
1158  DrawCircle(x+0.6*square,y1,r1,spec) ;
1159  DrawCircle(x+0.6*square,y1,r1/100,spec) ;
1160  }
1161  result = fs1 + TLatexFormSize(square,square,0);
1162  }
1163  else if (opHbar) {
1164  Double_t square = GetHeight()*spec.fSize/2;
1165  if (!fShow) {
1166  fs1 = Anal1(spec,text+5,length-5);
1167  } else {
1168  fs1 = Analyse(x+square,y,spec,text+5,length-5);
1169  TText hbar;
1170  hbar.SetTextFont(12);
1171  hbar.SetTextColor(spec.fColor);
1172  hbar.SetTextSize(spec.fSize);
1173  hbar.SetTextAngle(fTextAngle);
1174  hbar.SetTextAlign(11);
1175  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1176  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1177  Double_t angle = kPI*spec.fAngle/180.;
1178  Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
1179  Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
1180  hbar.PaintText(xx,yy,"h");
1181  DrawLine(x,y-0.8*square,x+0.75*square,y-square,spec);
1182  }
1183  result = fs1 + TLatexFormSize(square,square,0);
1184  }
1185  else if (opMinus) {
1186  Double_t square = GetHeight()*spec.fSize/2;
1187  if (!fShow) {
1188  fs1 = Anal1(spec,text+6,length-6);
1189  } else {
1190  fs1 = Analyse(x+square,y,spec,text+6,length-6);
1191  TText minus;
1192  minus.SetTextFont(122);
1193  minus.SetTextColor(spec.fColor);
1194  minus.SetTextSize(spec.fSize);
1195  minus.SetTextAngle(fTextAngle);
1196  minus.SetTextAlign(11);
1197  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1198  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1199  Double_t angle = kPI*spec.fAngle/180.;
1200  Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
1201  Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
1202  minus.PaintText(xx,yy,"-");
1203  }
1204  result = fs1 + TLatexFormSize(square,square,0);
1205  }
1206  else if (opPlus) {
1207  Double_t square = GetHeight()*spec.fSize/2;
1208  if (!fShow) {
1209  fs1 = Anal1(spec,text+5,length-5);
1210  } else {
1211  fs1 = Analyse(x+square,y,spec,text+5,length-5);
1212  TText plus;
1213  plus.SetTextFont(122);
1214  plus.SetTextColor(spec.fColor);
1215  plus.SetTextSize(spec.fSize);
1216  plus.SetTextAngle(fTextAngle);
1217  plus.SetTextAlign(11);
1218  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1219  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1220  Double_t angle = kPI*spec.fAngle/180.;
1221  Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
1222  Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
1223  plus.PaintText(xx,yy,"+");
1224  }
1225  result = fs1 + TLatexFormSize(square,square,0);
1226  }
1227  else if (opMp) {
1228  Double_t square = GetHeight()*spec.fSize/2;
1229  if (!fShow) {
1230  fs1 = Anal1(spec,text+3,length-3);
1231  } else {
1232  fs1 = Analyse(x+square,y,spec,text+3,length-3);
1233  TText mp;
1234  mp.SetTextFont(122);
1235  mp.SetTextColor(spec.fColor);
1236  mp.SetTextSize(spec.fSize);
1237  mp.SetTextAngle(fTextAngle+180);
1238  mp.SetTextAlign(11);
1239  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1240  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1241  Double_t angle = kPI*spec.fAngle/180.;
1242  Double_t xx = gPad->AbsPixeltoX(Int_t((x+square-xOrigin)*TMath::Cos(angle)+(y-1.25*square-yOrigin)*TMath::Sin(angle)+xOrigin));
1243  Double_t yy = gPad->AbsPixeltoY(Int_t((x+square-xOrigin)*TMath::Sin(-angle)+(y-1.25*square-yOrigin)*TMath::Cos(angle)+yOrigin));
1244  mp.PaintText(xx,yy,"\261");
1245  }
1246  result = fs1 + TLatexFormSize(square,square,0);
1247  }
1248  else if (opPerp) {
1249  Double_t square = GetHeight()*spec.fSize/1.4;
1250  if (!fShow) {
1251  fs1 = Anal1(spec,text+5,length-5);
1252  } else {
1253  fs1 = Analyse(x+0.5*square,y,spec,text+5,length-5);
1254  Double_t x0 = x + 0.50*square;
1255  Double_t x1 = x0 - 0.48*square;
1256  Double_t x2 = x0 + 0.48*square;
1257  Double_t y1 = y + 0.6*square;
1258  Double_t y2 = y1 - 1.3*square;
1259  DrawLine(x1,y1,x2,y1,spec);
1260  DrawLine(x0,y1,x0,y2,spec);
1261  }
1262  result = fs1;
1263  }
1264  else if (opBackslash) {
1265  Double_t square = GetHeight()*spec.fSize/2;
1266  if (!fShow) {
1267  fs1 = Anal1(spec,text+10,length-10);
1268  } else {
1269  fs1 = Analyse(x+square,y,spec,text+10,length-10);
1270  TText bs;
1271  bs.SetTextFont(GetTextFont());
1272  bs.SetTextColor(spec.fColor);
1273  bs.SetTextSize(spec.fSize);
1275  bs.SetTextAlign(11);
1276  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1277  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1278  Double_t angle = kPI*spec.fAngle/180.;
1279  Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
1280  Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
1281  bs.PaintText(xx,yy,"\\");
1282  }
1283  result = fs1 + TLatexFormSize(square,square,0);
1284  }
1285  else if (opParallel) {
1286  Double_t square = GetHeight()*spec.fSize/1.4;
1287  if (!fShow) {
1288  fs1 = Anal1(spec,text+9,length-9);
1289  } else {
1290  fs1 = Analyse(x+0.5*square,y,spec,text+9,length-9);
1291  Double_t x1 = x + 0.15*square;
1292  Double_t x2 = x + 0.45*square;
1293  Double_t y1 = y + 0.3*square;
1294  Double_t y2 = y1- 1.3*square;
1295  DrawLine(x1,y1,x1,y2,spec);
1296  DrawLine(x2,y1,x2,y2,spec);
1297  }
1298  result = fs1 + TLatexFormSize(square,square,0);
1299  }
1300  else if (opGreek>-1) {
1301  TextSpec_t newSpec = spec;
1302  newSpec.fFont = fItalic ? 152 : 122;
1303  char letter = 97 + opGreek;
1304  Double_t yoffset = 0.; // Greek letter too low
1305  if (opGreek>25) letter -= 58;
1306  if (opGreek == 52) letter = '\241'; //varUpsilon
1307  if (opGreek == 53) letter = '\316'; //epsilon
1308  if (!fShow) {
1309  fs1 = Anal1(newSpec,&letter,1);
1310  fs2 = Anal1(spec,text+strlen(tab[opGreek])+1,length-strlen(tab[opGreek])-1);
1311  Savefs(&fs1);
1312  } else {
1313  fs1 = Readfs();
1314  Analyse(x+fs1.Width(),y,spec,text+strlen(tab[opGreek])+1,length-strlen(tab[opGreek])-1);
1315  Analyse(x,y-yoffset,newSpec,&letter,1);
1316  }
1317  fs1.AddOver(TLatexFormSize(0,yoffset,0)) ;
1318  result = fs1+fs2;
1319  }
1320 
1321  else if (opSpec>-1) {
1322  TextSpec_t newSpec = spec;
1323  newSpec.fFont = fItalic ? 152 : 122;
1324  char letter = '\243' + opSpec;
1325  if(opSpec == 75 || opSpec == 76) {
1326  newSpec.fFont = GetTextFont();
1327  if (gVirtualX->InheritsFrom("TGCocoa")) {
1328  if (opSpec == 75) letter = '\201'; // AA Angstroem
1329  if (opSpec == 76) letter = '\214'; // aa Angstroem
1330  } else {
1331  if (opSpec == 75) letter = '\305'; // AA Angstroem
1332  if (opSpec == 76) letter = '\345'; // aa Angstroem
1333  }
1334  }
1335  if(opSpec == 80 || opSpec == 81) {
1336  if (opSpec == 80) letter = '\042'; // #forall
1337  if (opSpec == 81) letter = '\044'; // #exists
1338  }
1339  Double_t props, propi;
1340  props = 1.8 ; // scale factor for #sum(66)
1341  propi = 2.3 ; // scale factor for #int(79)
1342 
1343  if (opSpec==66 ) {
1344  newSpec.fSize = spec.fSize*props;
1345  } else if (opSpec==79) {
1346  newSpec.fSize = spec.fSize*propi;
1347  }
1348  if (!fShow) {
1349  fs1 = Anal1(newSpec,&letter,1);
1350  if (opSpec == 79 || opSpec == 66)
1351  fs1.Set(fs1.Width(),fs1.Over()*0.45,fs1.Over()*0.45);
1352 
1353  fs2 = Anal1(spec,text+strlen(tab2[opSpec])+1,length-strlen(tab2[opSpec])-1);
1354  Savefs(&fs1);
1355  } else {
1356  fs1 = Readfs();
1357  Analyse(x+fs1.Width(),y,spec,text+strlen(tab2[opSpec])+1,length-strlen(tab2[opSpec])-1);
1358  if (opSpec!=66 && opSpec!=79)
1359  Analyse(x,y,newSpec,&letter,1);
1360  else {
1361  Analyse(x,y+fs1.Under()/2.,newSpec,&letter,1);
1362  }
1363  }
1364  result = fs1+fs2;
1365  }
1366  else if (opAbove>-1) {
1367  if (!fShow) {
1368  fs1 = Anal1(spec,text+strlen(tab3[opAbove])+1,length-strlen(tab3[opAbove])-1);
1369  Savefs(&fs1);
1370  } else {
1371  fs1 = Readfs();
1372  Analyse(x,y,spec,text+strlen(tab3[opAbove])+1,length-strlen(tab3[opAbove])-1);
1373  Double_t sub = GetHeight()*spec.fSize/14;
1374  Double_t x1 , y1 , x2, y2, x3, x4;
1375  switch(opAbove) {
1376  case 0: // bar
1377  Double_t ypos ;
1378  ypos = y-fs1.Over()-sub ;//-GetHeight()*spec.fSize/4. ;
1379  DrawLine(x,ypos,x+fs1.Width(),ypos,spec);
1380  break;
1381  case 1: // vec
1382  Double_t y0 ;
1383  y0 = y-sub-fs1.Over() ;
1384  y1 = y0-GetHeight()*spec.fSize/8 ;
1385  x1 = x+fs1.Width() ;
1386  DrawLine(x,y1,x1,y1,spec);
1387  DrawLine(x1,y1,x1-GetHeight()*spec.fSize/4,y0-GetHeight()*spec.fSize/4,spec);
1388  DrawLine(x1,y1,x1-GetHeight()*spec.fSize/4,y0,spec);
1389  break;
1390  case 2: // dot
1391  x1 = x+fs1.Width()/2-3*sub/4 ;
1392  x2 = x+fs1.Width()/2+3*sub/4 ;
1393  y1 = y-sub-fs1.Over() ;
1394  DrawLine(x1,y1,x2,y1,spec);
1395  break;
1396  case 3: // hat
1397  x2 = x+fs1.Width()/2 ;
1398  y1 = y -9*sub;
1399  y2 = y1-2*sub;
1400  x1 = x2-fs1.Width()/3 ;
1401  x3 = x2+fs1.Width()/3 ;
1402  DrawLine(x1,y1,x2,y2,spec);
1403  DrawLine(x2,y2,x3,y1,spec);
1404  break;
1405  case 4: // ddot
1406  x1 = x+fs1.Width()/2-9*sub/4 ;
1407  x2 = x+fs1.Width()/2-3*sub/4 ;
1408  x3 = x+fs1.Width()/2+9*sub/4 ;
1409  x4 = x+fs1.Width()/2+3*sub/4 ;
1410  y1 = y-sub-fs1.Over() ;
1411  DrawLine(x1,y1,x2,y1,spec);
1412  DrawLine(x3,y1,x4,y1,spec);
1413  break;
1414  case 5: // acute
1415  x1 = x+fs1.Width()/2;
1416  y1 = y +sub -fs1.Over() ;
1417  x2 = x1 +3*sub;
1418  y2 = y1 -2.5*sub;
1419  DrawLine(x1,y1,x2,y2,spec);
1420  break;
1421  case 6: // grave
1422  x1 = x+fs1.Width()/2-sub;
1423  y1 = y-sub-fs1.Over() ;
1424  x2 = x1 +2*sub;
1425  y2 = y1 +2*sub;
1426  DrawLine(x1,y1,x2,y2,spec);
1427  break;
1428  case 7: // check
1429  x1 = x+fs1.Width()/2 ;
1430  x2 = x1 -2*sub ;
1431  x3 = x1 +2*sub ;
1432  y1 = y-sub-fs1.Over() ;
1433  DrawLine(x2,y-3*sub-fs1.Over(),x1,y1,spec);
1434  DrawLine(x3,y-3*sub-fs1.Over(),x1,y1,spec);
1435  break;
1436  case 8: // tilde
1437  x2 = x+fs1.Width()/2 ;
1438  y2 = y -fs1.Over() ;
1439  {
1440  // tilde must be drawn separately on screen and on PostScript
1441  // because an adjustment is required along Y for PostScript.
1442  TVirtualPS *saveps = gVirtualPS;
1443  if (gVirtualPS) gVirtualPS = 0;
1444  Double_t y22 = y2;
1445  if (gVirtualX->InheritsFrom("TGCocoa")) y2 -= 4.7*sub;
1446  Double_t sinang = TMath::Sin(spec.fAngle/180*kPI);
1447  Double_t cosang = TMath::Cos(spec.fAngle/180*kPI);
1448  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1449  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1450  Double_t xx = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y2-yOrigin)*sinang+xOrigin));
1451  Double_t yy = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y2-yOrigin)*cosang+yOrigin));
1452  TText tilde;
1453  tilde.SetTextFont(fTextFont);
1454  tilde.SetTextColor(spec.fColor);
1455  tilde.SetTextSize(0.9*spec.fSize);
1456  tilde.SetTextAlign(22);
1457  tilde.SetTextAngle(fTextAngle);
1458  tilde.PaintText(xx,yy,"~");
1459  if (saveps) {
1460  gVirtualPS = saveps;
1461  if (!strstr(gVirtualPS->GetTitle(),"IMG")) y22 -= 4*sub;
1462  xx = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y22-yOrigin)*sinang+xOrigin));
1463  yy = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y22-yOrigin)*cosang+yOrigin));
1464  gVirtualPS->SetTextAlign(22);
1465  gVirtualPS->Text(xx, yy, "~");
1466  }
1467  }
1468  break;
1469  case 9: // slash
1470  x1 = x + 0.8*fs1.Width();
1471  y1 = y -fs1.Over() ;
1472  x2 = x + 0.3*fs1.Width();
1473  y2 = y1 + 1.2*fs1.Height();
1474  DrawLine(x1,y1,x2,y2,spec);
1475  break;
1476  }
1477  }
1478  Double_t div = 3;
1479  if (opAbove==1) div=4;
1480  result.Set(fs1.Width(),fs1.Over()+GetHeight()*spec.fSize/div,fs1.Under());
1481  }
1482  else if (opSquareBracket) { // operator #[]{arg}
1483  Double_t l = GetHeight()*spec.fSize/4;
1484  Double_t l2 = l/2 ;
1485  if (!fShow) {
1486  fs1 = Anal1(spec,text+3,length-3);
1487  Savefs(&fs1);
1488  } else {
1489  fs1 = Readfs();
1490  Analyse(x+l2+l,y,spec,text+3,length-3);
1491  DrawLine(x+l2,y-fs1.Over(),x+l2,y+fs1.Under(),spec);
1492  DrawLine(x+l2,y-fs1.Over(),x+l2+l,y-fs1.Over(),spec);
1493  DrawLine(x+l2,y+fs1.Under(),x+l2+l,y+fs1.Under(),spec);
1494  DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+2*l,y+fs1.Under(),spec);
1495  DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+l,y-fs1.Over(),spec);
1496  DrawLine(x+l2+fs1.Width()+2*l,y+fs1.Under(),x+l2+fs1.Width()+l,y+fs1.Under(),spec);
1497  }
1498  result.Set(fs1.Width()+3*l,fs1.Over(),fs1.Under());
1499  }
1500  else if (opParen) { // operator #(){arg}
1501  Double_t l = GetHeight()*spec.fSize/4;
1502  Double_t radius2,radius1 , dw, l2 = l/2 ;
1503  Double_t angle = 35 ;
1504  if (!fShow) {
1505  fs1 = Anal1(spec,text+3,length-3);
1506  Savefs(&fs1);
1507  radius2 = fs1.Height() ;
1508  radius1 = radius2 * 2 / 3;
1509  dw = radius1*(1 - TMath::Cos(kPI*angle/180)) ;
1510  } else {
1511  fs1 = Readfs();
1512  radius2 = fs1.Height();
1513  radius1 = radius2 * 2 / 3;
1514  dw = radius1*(1 - TMath::Cos(kPI*angle/180)) ;
1515  Double_t x1 = x+l2+radius1 ;
1516  Double_t x2 = x+5*l2+2*dw+fs1.Width()-radius1 ;
1517  Double_t y1 = y - (fs1.Over() - fs1.Under())/2. ;
1518  DrawParenthesis(x1,y1,radius1,radius2,180-angle,180+angle,spec) ;
1519  DrawParenthesis(x2,y1,radius1,radius2,360-angle,360+angle,spec) ;
1520  Analyse(x+3*l2+dw,y,spec,text+3,length-3);
1521  }
1522  // result = TLatexFormSize(fs1.Width()+3*l,fs1.Over(),fs1.Under());
1523  result.Set(fs1.Width()+3*l+2*dw,fs1.Over(),fs1.Under());
1524  }
1525  else if (opAbs) { // operator #||{arg}
1526  Double_t l = GetHeight()*spec.fSize/4;
1527  Double_t l2 = l/2 ;
1528  if (!fShow) {
1529  fs1 = Anal1(spec,text+3,length-3);
1530  Savefs(&fs1);
1531  } else {
1532  fs1 = Readfs();
1533  Analyse(x+l2+l,y,spec,text+3,length-3);
1534  DrawLine(x+l2,y-fs1.Over(),x+l2,y+fs1.Under(),spec);
1535  DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+2*l,y+fs1.Under(),spec);
1536  }
1537  result.Set(fs1.Width()+3*l,fs1.Over(),fs1.Under());
1538  }
1539  else if (opBigCurly) { // big curly bracket #{}{arg}
1540  Double_t l = GetHeight()*spec.fSize/4;
1541  Double_t l2 = l/2 ;
1542  Double_t l8 , ltip;
1543 
1544  if (!fShow) {
1545  fs1 = Anal1(spec,text+3,length-3);
1546  l8 = fs1.Height()/8 ;
1547  ltip = TMath::Min(l8,l) ;
1548  l = ltip ;
1549  Savefs(&fs1);
1550  } else {
1551  fs1 = Readfs();
1552  Double_t y2 = y + (fs1.Under()-fs1.Over())/2 ;
1553  l8 = fs1.Height()/8 ;
1554  ltip = TMath::Min(l8,l) ;
1555  l = ltip ;
1556  Analyse(x+l+ltip+l2,y,spec,text+3,length-3);
1557  // Draw open curly bracket
1558  // Vertical lines
1559  DrawLine(x+l2+ltip,y-fs1.Over(),x+l2+ltip,y2-ltip,spec);
1560  DrawLine(x+l2+ltip,y2+ltip,x+l2+ltip,y+fs1.Under(),spec);
1561  // top and bottom lines
1562  DrawLine(x+l2+ltip,y-fs1.Over(),x+l2+ltip+l,y-fs1.Over(),spec);
1563  DrawLine(x+l2+ltip,y+fs1.Under(),x+l2+ltip+l,y+fs1.Under(),spec);
1564  // < sign
1565  DrawLine(x+l2,y2,x+l2+ltip,y2-ltip,spec);
1566  DrawLine(x+l2,y2,x+l2+ltip,y2+ltip,spec);
1567 
1568  // Draw close curly bracket
1569  // vertical lines
1570  DrawLine(x+l2+ltip+fs1.Width()+2*l,y-fs1.Over(),x+l2+ltip+fs1.Width()+2*l,y2-ltip,spec);
1571  DrawLine(x+l2+ltip+fs1.Width()+2*l,y2+ltip,x+l2+ltip+fs1.Width()+2*l,y+fs1.Under(),spec);
1572  // Top and bottom lines
1573  DrawLine(x+l2+fs1.Width()+l+ltip,y-fs1.Over(),x+l2+ltip+fs1.Width()+2*l,y-fs1.Over(),spec);
1574  DrawLine(x+l2+fs1.Width()+l+ltip,y+fs1.Under(),x+l2+ltip+fs1.Width()+2*l,y+fs1.Under(),spec);
1575  // > sign
1576  DrawLine(x+l2+ltip+2*l+fs1.Width(),y2-ltip,x+l2+2*l+2*ltip+fs1.Width(),y2,spec);
1577  DrawLine(x+l2+ltip+2*l+fs1.Width(),y2+ltip,x+l2+2*l+2*ltip+fs1.Width(),y2,spec);
1578  }
1579  result.Set(fs1.Width()+3*l+2*ltip,fs1.Over(),fs1.Under()) ;;
1580  }
1581  else if (opFrac>-1) { // \frac found
1582  if (opCurlyCurly==-1) { // }{ not found
1583  // arguments missing for \frac
1584  fError = "Missing denominator for #frac";
1585  delete[] text;
1586  return TLatexFormSize(0,0,0);
1587  }
1588  Double_t height = GetHeight()*spec.fSize/8;
1589  if (!fShow) {
1590  fs1 = Anal1(spec,text+opFrac+6,opCurlyCurly-opFrac-6);
1591  fs2 = Anal1(spec,text+opCurlyCurly+2,length-opCurlyCurly-3);
1592  Savefs(&fs1);
1593  Savefs(&fs2);
1594  } else {
1595  fs2 = Readfs();
1596  fs1 = Readfs();
1597  Double_t addW1,addW2;
1598  if (fs1.Width()<fs2.Width()) {
1599  addW1 = (fs2.Width()-fs1.Width())/2;
1600  addW2 = 0;
1601  } else {
1602  addW1 = 0;
1603  addW2 = (fs1.Width()-fs2.Width())/2;
1604  }
1605  Analyse(x+addW2,y+fs2.Over()-height,spec,text+opCurlyCurly+2,length-opCurlyCurly-3); // denominator
1606  Analyse(x+addW1,y-fs1.Under()-3*height,spec,text+opFrac+6,opCurlyCurly-opFrac-6); //numerator
1607 
1608  DrawLine(x,y-2*height,x+TMath::Max(fs1.Width(),fs2.Width()),y-2*height,spec);
1609  }
1610 
1611  result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Height()+3*height,fs2.Height()-height);
1612 
1613  }
1614  else if (opSplitLine>-1) { // \splitline found
1615  if (opCurlyCurly==-1) { // }{ not found
1616  // arguments missing for \splitline
1617  fError = "Missing second line for #splitline";
1618  delete[] text;
1619  return TLatexFormSize(0,0,0);
1620  }
1621  Double_t height = GetHeight()*spec.fSize/8;
1622  if (!fShow) {
1623  fs1 = Anal1(spec,text+opSplitLine+11,opCurlyCurly-opSplitLine-11);
1624  fs2 = Anal1(spec,text+opCurlyCurly+2,length-opCurlyCurly-3);
1625  Savefs(&fs1);
1626  Savefs(&fs2);
1627  } else {
1628  fs2 = Readfs();
1629  fs1 = Readfs();
1630  Analyse(x,y+fs2.Over()-height,spec,text+opCurlyCurly+2,length-opCurlyCurly-3); // second line
1631  Analyse(x,y-fs1.Under()-3*height,spec,text+opSplitLine+11,opCurlyCurly-opSplitLine-11); //first line
1632  }
1633 
1634  result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Height()+3*height,fs2.Height()-height);
1635 
1636  }
1637  else if (opSqrt>-1) { // \sqrt found
1638  if (!fShow) {
1639  if (opSquareCurly>-1) {
1640  // power nth #sqrt[n]{arg}
1641  fs1 = Anal1(specNewSize,text+opSqrt+6,opSquareCurly-opSqrt-6);
1642  fs2 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
1643  Savefs(&fs1);
1644  Savefs(&fs2);
1645  result.Set(fs2.Width()+ GetHeight()*spec.fSize/10+TMath::Max(GetHeight()*spec.fSize/2,(Double_t)fs1.Width()),
1646  fs2.Over()+fs1.Height()+GetHeight()*spec.fSize/4,fs2.Under());
1647  } else {
1648  fs1 = Anal1(spec,text+opSqrt+5,length-opSqrt-5);
1649  Savefs(&fs1);
1650  result.Set(fs1.Width()+GetHeight()*spec.fSize/2,fs1.Over()+GetHeight()*spec.fSize/4,fs1.Under());
1651  }
1652  } else {
1653  if (opSquareCurly>-1) { // ]{
1654  fs2 = Readfs();
1655  fs1 = Readfs();
1656  Double_t pas = TMath::Max(GetHeight()*spec.fSize/2,(Double_t)fs1.Width());
1657  Double_t pas2 = pas + GetHeight()*spec.fSize/10;
1658  Double_t y1 = y-fs2.Over() ;
1659  Double_t y2 = y+fs2.Under() ;
1660  Double_t y3 = y1-GetHeight()*spec.fSize/4;
1661  Analyse(x+pas2,y,spec,text+opSquareCurly+1,length-opSquareCurly-1);
1662  Analyse(x,y-fs2.Over()-fs1.Under(),specNewSize,text+opSqrt+6,opSquareCurly-opSqrt-6); // indice
1663  DrawLine(x,y1,x+pas,y2,spec);
1664  DrawLine(x+pas,y2,x+pas,y3,spec);
1665  DrawLine(x+pas,y3,x+pas2+fs2.Width(),y3,spec);
1666  } else {
1667  fs1 = Readfs();
1668  Double_t x1 = x+GetHeight()*spec.fSize*2/5 ;
1669  Double_t x2 = x+GetHeight()*spec.fSize/2+fs1.Width() ;
1670  Double_t y1 = y-fs1.Over() ;
1671  Double_t y2 = y+fs1.Under() ;
1672  Double_t y3 = y1-GetHeight()*spec.fSize/4;
1673 
1674  Analyse(x+GetHeight()*spec.fSize/2,y,spec,text+opSqrt+6,length-opSqrt-7);
1675 
1676  Short_t lineW = GetLineWidth();
1677  SetLineWidth(1);
1678  Double_t dx = (y2-y3)/8;
1679  UInt_t a,d;
1681  if (a>12) SetLineWidth(TMath::Max(2,(Int_t)(dx/2)));
1682  DrawLine(x1-2*dx,y1,x1-dx,y2,spec);
1683  if (a>12) SetLineWidth(TMath::Max(1,(Int_t)(dx/4)));
1684  DrawLine(x1-dx,y2,x1,y3,spec);
1685  DrawLine(x1,y3,x2,y3,spec);
1686  SetLineWidth(lineW);
1687  }
1688  }
1689  }
1690  else if (opColor>-1) { // \color found
1691  if (opSquareCurly==-1) {
1692  // color number is not specified
1693  fError = "Missing color number. Syntax is #color[(Int_t)nb]{ ... }";
1694  delete[] text;
1695  return TLatexFormSize(0,0,0);
1696  }
1697  TextSpec_t newSpec = spec;
1698  Char_t *nb = new Char_t[opSquareCurly-opColor-6];
1699  strncpy(nb,text+opColor+7,opSquareCurly-opColor-7);
1700  nb[opSquareCurly-opColor-7] = 0;
1701  if (sscanf(nb,"%d",&newSpec.fColor) < 1) {
1702  delete[] nb;
1703  // color number is invalid
1704  fError = "Invalid color number. Syntax is #color[(Int_t)nb]{ ... }";
1705  delete[] text;
1706  return TLatexFormSize(0,0,0);
1707  }
1708  delete[] nb;
1709  if (!fShow) {
1710  result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1711  } else {
1712  Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1713  }
1714  }
1715  else if (opFont>-1) { // \font found
1716  if (opSquareCurly==-1) {
1717  // font number is not specified
1718  fError = "Missing font number. Syntax is #font[nb]{ ... }";
1719  delete[] text;
1720  return TLatexFormSize(0,0,0);
1721  }
1722  TextSpec_t newSpec = spec;
1723  Char_t *nb = new Char_t[opSquareCurly-opFont-5];
1724  strncpy(nb,text+opFont+6,opSquareCurly-opFont-6);
1725  nb[opSquareCurly-opFont-6] = 0;
1726  if (sscanf(nb,"%d",&newSpec.fFont) < 1) {
1727  delete[] nb;
1728  // font number is invalid
1729  fError = "Invalid font number. Syntax is #font[(Int_t)nb]{ ... }";
1730  delete[] text;
1731  return TLatexFormSize(0,0,0);
1732  }
1733  delete[] nb;
1734  if (!fShow) {
1735  result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1736  } else {
1737  Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1738  }
1739  }
1740  else if (opKern>-1) { // #kern found
1741  if (opSquareCurly==-1) {
1742  // horizontal shift is not specified
1743  fError = "Missing horizontal shift number. Syntax is #kern[dx]{ ... }";
1744  delete[] text;
1745  return TLatexFormSize(0,0,0);
1746  }
1747  Char_t *dxc = new Char_t[opSquareCurly-opKern-5];
1748  strncpy(dxc,text+opKern+6,opSquareCurly-opKern-6);
1749  dxc[opSquareCurly-opKern-6] = 0;
1750  Float_t dx = 0;
1751  if (sscanf(dxc,"%f",&dx) < 1) {
1752  delete[] dxc;
1753  // horizontal shift number is invalid
1754  fError = "Invalid horizontal shift number. Syntax is #kern[(Float_t)dx]{ ... }";
1755  delete[] text;
1756  return TLatexFormSize(0,0,0);
1757  }
1758  delete[] dxc;
1759  if (!fShow) {
1760  fs1 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
1761  Savefs(&fs1);
1762  Double_t ddx = dx * fs1.Width();
1763  result = TLatexFormSize(fs1.Width() + ddx, fs1.Over(), fs1.Under());
1764  } else {
1765  fs1 = Readfs();
1766  Double_t ddx = dx * fs1.Width();
1767  Analyse(x + ddx,y,spec,text+opSquareCurly+1,length-opSquareCurly-1);
1768  }
1769  }
1770  else if (opLower>-1) { // #lower found
1771  if (opSquareCurly==-1) {
1772  // vertical shift is not specified
1773  fError = "Missing vertical shift number. Syntax is #lower[dy]{ ... }";
1774  delete[] text;
1775  return TLatexFormSize(0,0,0);
1776  }
1777  Char_t *dyc = new Char_t[opSquareCurly-opLower-6];
1778  strncpy(dyc,text+opLower+7,opSquareCurly-opLower-7);
1779  dyc[opSquareCurly-opLower-7] = 0;
1780  Float_t dy = 0;
1781  if (sscanf(dyc,"%f",&dy) < 1) {
1782  delete[] dyc;
1783  // vertical shift number is invalid
1784  fError = "Invalid vertical shift number. Syntax is #lower[(Float_t)dy]{ ... }";
1785  delete[] text;
1786  return TLatexFormSize(0,0,0);
1787  }
1788  delete[] dyc;
1789  if (!fShow) {
1790  fs1 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
1791  Savefs(&fs1);
1792  Double_t ddy = dy * (fs1.Over() + fs1.Under());
1793  result = TLatexFormSize(fs1.Width(), fs1.Over() + ddy, fs1.Under() + ddy);
1794  } else {
1795  fs1 = Readfs();
1796  Double_t ddy = dy * (fs1.Over() + fs1.Under());
1797  Analyse(x,y + ddy,spec,text+opSquareCurly+1,length-opSquareCurly-1);
1798  }
1799  }
1800  else if (opScale>-1) { // \scale found
1801  if (opSquareCurly==-1) {
1802  // scale factor is not specified
1803  fError = "Missing scale factor. Syntax is #scale[(Double_t)nb]{ ... }";
1804  delete[] text;
1805  return TLatexFormSize(0,0,0);
1806  }
1807  TextSpec_t newSpec = spec;
1808  Char_t *nb = new Char_t[opSquareCurly-opScale-6];
1809  strncpy(nb,text+opScale+7,opSquareCurly-opScale-7);
1810  nb[opSquareCurly-opScale-7] = 0;
1811  if (sscanf(nb,"%lf",&newSpec.fSize) < 1) {
1812  delete[] nb;
1813  // scale factor is invalid
1814  fError = "Invalid scale factor. Syntax is #factor[(Double_t)nb]{ ... }";
1815  delete[] text;
1816  return TLatexFormSize(0,0,0);
1817  }
1818  newSpec.fSize *= spec.fSize;
1819  delete[] nb;
1820  if (!fShow) {
1821  result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1822  } else {
1823  Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
1824  }
1825  }
1826  else if (opBf>-1) { // operator #bf{arg}
1827  TextSpec_t newSpec = spec;
1828  Int_t lut[] = {3, 13, 1, 6, 7, 4, 5, 10, 11, 8, 9, 12, 2, 14, 15};
1829  Int_t fontId = (newSpec.fFont/10);
1830  if ((fontId >= 1) && (fontId <= (Int_t)(sizeof(lut)/sizeof(lut[0])))) fontId = lut[fontId-1];
1831  newSpec.fFont = fontId*10 + newSpec.fFont%10;
1832  if (!fShow) {
1833  fs1 = Anal1(newSpec,text+3,length-3);
1834  Savefs(&fs1);
1835  } else {
1836  fs1 = Readfs();
1837  Analyse(x,y,newSpec,text+3,length-3);
1838  }
1839  result = fs1;
1840  }
1841  else if (opMbox>-1) { // dummy operator #mbox{arg}
1842  TextSpec_t newSpec = spec;
1843  if (!fShow) {
1844  fs1 = Anal1(newSpec,text+5,length-5);
1845  Savefs(&fs1);
1846  } else {
1847  fs1 = Readfs();
1848  Analyse(x,y,newSpec,text+5,length-5);
1849  }
1850  result = fs1;
1851  }
1852  else if (opIt>-1) { // operator #it{arg}
1853  TextSpec_t newSpec = spec;
1854  Int_t lut[] = {13, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 15, 1, 14, 12};
1855  Int_t fontId = (newSpec.fFont/10);
1856  if ((fontId >= 1) && (fontId <= (Int_t)(sizeof(lut)/sizeof(lut[0])))) fontId = lut[fontId-1];
1857  newSpec.fFont = fontId*10 + newSpec.fFont%10;
1858  fItalic = !fItalic;
1859  if (!fShow) {
1860  fs1 = Anal1(newSpec,text+3,length-3);
1861  Savefs(&fs1);
1862  } else {
1863  fs1 = Readfs();
1864  Analyse(x,y,newSpec,text+3,length-3);
1865  }
1866  fItalic = !fItalic;
1867  result = fs1;
1868  }
1869  else { // no operators found, it is a character string
1870  SetTextSize(spec.fSize);
1871  SetTextAngle(spec.fAngle);
1872  SetTextColor(spec.fColor);
1873  SetTextFont(spec.fFont);
1874  SetTextAlign(11);
1875  TAttText::Modify();
1876  UInt_t w=0,h=0;
1877 
1878  Int_t leng = strlen(text) ;
1879 
1880  quote1 = quote2 = kFALSE ;
1881  Char_t *p ;
1882  for (i=0 ; i<leng ; i++) {
1883  switch (text[i]) {
1884  case '\'' : quote1 = !quote1 ; break ; // single quote symbol not correctly interpreted when PostScript
1885  case '"' : quote2 = !quote2 ; break ;
1886  }
1887  //if (quote1 || quote2) continue ;
1888  if (text[i] == '@') { // @ symbol not correctly interpreted when PostScript
1889  p = &text[i] ;
1890  if ( *(p+1) == '{' || *(p+1) == '}' || *(p+1) == '[' || *(p+1) == ']') {
1891  while (*p != 0) {
1892  *p = *(p+1) ; p++ ;
1893  }
1894  leng-- ;
1895  }
1896  }
1897  }
1898  text[leng] = 0 ;
1899 
1900  if (fShow) {
1901  // paint the Latex sub-expression per sub-expression
1902  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1903  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1904  Double_t angle = kPI*spec.fAngle/180.;
1905  Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
1906  Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
1907  gPad->PaintText(xx,yy,text);
1908  } else {
1909  GetTextExtent(w,h,text);
1910  Double_t width = w;
1911  UInt_t a,d;
1913  fs1.Set(width,a,d);
1914  }
1915 
1916  result = fs1;
1917  }
1918 
1919  delete[] text;
1920 
1921  return result;
1922 }
1923 
1924 ////////////////////////////////////////////////////////////////////////////////
1925 /// Make a copy of this object with the new parameters
1926 /// And copy object attributes
1927 
1929 {
1930  TLatex *newtext = new TLatex(x, y, text);
1931  TAttText::Copy(*newtext);
1932  newtext->SetBit(kCanDelete);
1933  if (TestBit(kTextNDC)) newtext->SetNDC();
1934  newtext->AppendPad();
1935  return newtext;
1936 }
1937 
1938 ////////////////////////////////////////////////////////////////////////////////
1939 /// Draw this TLatex with new coordinates in NDC.
1940 
1942 {
1943  TLatex *newtext = DrawLatex(x, y, text);
1944  newtext->SetNDC();
1945  return newtext;
1946 }
1947 
1948 ////////////////////////////////////////////////////////////////////////////////
1949 /// Draw a line in a Latex formula
1950 
1952 {
1953  Double_t sinang = TMath::Sin(spec.fAngle/180*kPI);
1954  Double_t cosang = TMath::Cos(spec.fAngle/180*kPI);
1955  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1956  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1957  Double_t xx = gPad->AbsPixeltoX(Int_t((x1-xOrigin)*cosang+(y1-yOrigin)*sinang+xOrigin));
1958  Double_t yy = gPad->AbsPixeltoY(Int_t((x1-xOrigin)*-sinang+(y1-yOrigin)*cosang+yOrigin));
1959 
1960  Double_t xx2 = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y2-yOrigin)*sinang+xOrigin));
1961  Double_t yy2 = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y2-yOrigin)*cosang+yOrigin));
1962 
1963  SetLineColor(spec.fColor);
1964  TAttLine::Modify();
1965  gPad->PaintLine(xx,yy,xx2,yy2);
1966 }
1967 
1968 ////////////////////////////////////////////////////////////////////////////////
1969 /// Draw an arc of ellipse in a Latex formula (right or left parenthesis)
1970 
1972 {
1973  if (r < 1) r = 1;
1974  Double_t sinang = TMath::Sin(spec.fAngle/180*kPI);
1975  Double_t cosang = TMath::Cos(spec.fAngle/180*kPI);
1976  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
1977  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
1978 
1979  const Int_t np = 40;
1980  Double_t dphi = 2*kPI/np;
1981  Double_t x[np+3], y[np+3];
1982  Double_t angle,dx,dy;
1983 
1984  SetLineColor(spec.fColor);
1985  TAttLine::Modify(); //Change line attributes only if necessary
1986 
1987  for (Int_t i=0;i<=np;i++) {
1988  angle = Double_t(i)*dphi;
1989  dx = r*TMath::Cos(angle) +x1 -xOrigin;
1990  dy = r*TMath::Sin(angle) +y1 -yOrigin;
1991  x[i] = gPad->AbsPixeltoX(Int_t( dx*cosang+ dy*sinang +xOrigin));
1992  y[i] = gPad->AbsPixeltoY(Int_t(-dx*sinang+ dy*cosang +yOrigin));
1993  }
1994  gPad->PaintPolyLine(np+1,x,y);
1995 }
1996 
1997 ////////////////////////////////////////////////////////////////////////////////
1998 /// Draw an arc of ellipse in a Latex formula (right or left parenthesis)
1999 
2001  Double_t phimin, Double_t phimax, TextSpec_t spec )
2002 {
2003  if (r1 < 1) r1 = 1;
2004  if (r2 < 1) r2 = 1;
2005  Double_t sinang = TMath::Sin(spec.fAngle/180*kPI);
2006  Double_t cosang = TMath::Cos(spec.fAngle/180*kPI);
2007  Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
2008  Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
2009 
2010  const Int_t np = 40;
2011  Double_t dphi = (phimax-phimin)*kPI/(180*np);
2012  Double_t x[np+3], y[np+3];
2013  Double_t angle,dx,dy ;
2014 
2015  SetLineColor(spec.fColor);
2016  TAttLine::Modify(); //Change line attributes only if necessary
2017 
2018  for (Int_t i=0;i<=np;i++) {
2019  angle = phimin*kPI/180 + Double_t(i)*dphi;
2020  dx = r1*TMath::Cos(angle) +x1 -xOrigin;
2021  dy = r2*TMath::Sin(angle) +y1 -yOrigin;
2022  x[i] = gPad->AbsPixeltoX(Int_t( dx*cosang+dy*sinang +xOrigin));
2023  y[i] = gPad->AbsPixeltoY(Int_t(-dx*sinang+dy*cosang +yOrigin));
2024  }
2025  gPad->PaintPolyLine(np+1,x,y);
2026 }
2027 
2028 ////////////////////////////////////////////////////////////////////////////////
2029 /// Paint.
2030 
2031 void TLatex::Paint(Option_t *)
2032 {
2033  Double_t xsave = fX;
2034  Double_t ysave = fY;
2035  if (TestBit(kTextNDC)) {
2036  fX = gPad->GetX1() + xsave*(gPad->GetX2() - gPad->GetX1());
2037  fY = gPad->GetY1() + ysave*(gPad->GetY2() - gPad->GetY1());
2039  } else {
2040  PaintLatex(gPad->XtoPad(fX),gPad->YtoPad(fY),GetTextAngle(),GetTextSize(),GetTitle());
2041  }
2042  fX = xsave;
2043  fY = ysave;
2044 }
2045 
2046 ////////////////////////////////////////////////////////////////////////////////
2047 /// Main drawing function
2048 ///
2049 /// Warning: Unlike most others "XYZ::PaintXYZ" methods, PaintLatex modifies
2050 /// the TLatex data members.
2051 
2052 void TLatex::PaintLatex(Double_t x, Double_t y, Double_t angle, Double_t size, const Char_t *text1)
2053 {
2054  if (size<=0 || strlen(text1) <= 0) return; // do not paint empty text or text with size <= 0
2055 
2056  TAttText::Modify(); // Change text attributes only if necessary.
2057 
2058  TVirtualPS *saveps = gVirtualPS;
2059 
2060  if (gVirtualPS) {
2061  if (gVirtualPS->InheritsFrom("TTeXDump")) {
2062  gVirtualPS->SetTextAngle(angle);
2063  TString t(text1);
2064  if (t.Index("#")>=0 || t.Index("^")>=0 || t.Index("\\")>=0) {
2065  t.ReplaceAll("#LT","\\langle");
2066  t.ReplaceAll("#GT","\\rangle");
2067  t.ReplaceAll("#club","\\clubsuit");
2068  t.ReplaceAll("#spade","\\spadesuit");
2069  t.ReplaceAll("#heart","\\heartsuit");
2070  t.ReplaceAll("#diamond","\\diamondsuit");
2071  t.ReplaceAll("#voidn","\\wp");
2072  t.ReplaceAll("#voidb","f");
2073  t.ReplaceAll("#ocopyright","\\copyright");
2074  t.ReplaceAll("#trademark","TM");
2075  t.ReplaceAll("#void3","TM");
2076  t.ReplaceAll("#oright","R");
2077  t.ReplaceAll("#void1","R");
2078  t.ReplaceAll("#3dots","\\ldots");
2079  t.ReplaceAll("#lbar","\\mid");
2080  t.ReplaceAll("#bar","\\wwbar");
2081  t.ReplaceAll("#void8","\\mid");
2082  t.ReplaceAll("#divide","\\div");
2083  t.ReplaceAll("#Jgothic","\\Im");
2084  t.ReplaceAll("#Rgothic","\\Re");
2085  t.ReplaceAll("#doublequote","\"");
2086  t.ReplaceAll("#plus","+");
2087  t.ReplaceAll("#minus","-");
2088  t.ReplaceAll("#/","/");
2089  t.ReplaceAll("#upoint",".");
2090  t.ReplaceAll("#aa","\\mbox{\\aa}");
2091  t.ReplaceAll("#AA","\\mbox{\\AA}");
2092 
2093  t.ReplaceAll("#omicron","o");
2094  t.ReplaceAll("#Alpha","A");
2095  t.ReplaceAll("#Beta","B");
2096  t.ReplaceAll("#Epsilon","E");
2097  t.ReplaceAll("#Zeta","Z");
2098  t.ReplaceAll("#Eta","H");
2099  t.ReplaceAll("#Iota","I");
2100  t.ReplaceAll("#Kappa","K");
2101  t.ReplaceAll("#Mu","M");
2102  t.ReplaceAll("#Nu","N");
2103  t.ReplaceAll("#Omicron","O");
2104  t.ReplaceAll("#Rho","P");
2105  t.ReplaceAll("#Tau","T");
2106  t.ReplaceAll("#Chi","X");
2107  t.ReplaceAll("#varomega","\\varpi");
2108 
2109  t.ReplaceAll("#varUpsilon","?");
2110  t.ReplaceAll("#corner","?");
2111  t.ReplaceAll("#ltbar","?");
2112  t.ReplaceAll("#bottombar","?");
2113  t.ReplaceAll("#notsubset","?");
2114  t.ReplaceAll("#arcbottom","?");
2115  t.ReplaceAll("#cbar","?");
2116  t.ReplaceAll("#arctop","?");
2117  t.ReplaceAll("#topbar","?");
2118  t.ReplaceAll("#arcbar","?");
2119  t.ReplaceAll("#downleftarrow","?");
2120  t.ReplaceAll("#splitline","\\genfrac{}{}{0pt}{}");
2121 
2122  t.ReplaceAll("#","\\");
2123  t.ReplaceAll("%","\\%");
2124  }
2125  gVirtualPS->Text(x,y,t.Data());
2126  } else {
2127  Bool_t saveb = gPad->IsBatch();
2128  gPad->SetBatch(kTRUE);
2129  if (!PaintLatex1( x, y, angle, size, text1)) {
2130  if (saveps) gVirtualPS = saveps;
2131  return;
2132  }
2133  gPad->SetBatch(saveb);
2134  }
2135  gVirtualPS = 0;
2136  }
2137 
2138  if (!gPad->IsBatch()) PaintLatex1( x, y, angle, size, text1);
2139  if (saveps) gVirtualPS = saveps;
2140 }
2141 
2142 ////////////////////////////////////////////////////////////////////////////////
2143 /// Drawing function
2144 
2145 Int_t TLatex::PaintLatex1(Double_t x, Double_t y, Double_t angle, Double_t size, const Char_t *text1)
2146 {
2147  TString newText = text1;
2148  if( newText.Length() == 0) return 0;
2149  newText.ReplaceAll("#hbox","#mbox");
2150 
2151  fError = 0 ;
2152  if (CheckLatexSyntax(newText)) {
2153  std::cout<<"\n*ERROR<TLatex>: "<<fError<<std::endl;
2154  std::cout<<"==> "<<text1<<std::endl;
2155  return 0;
2156  }
2157  fError = 0 ;
2158 
2159  // Do not use Latex if font is low precision.
2160  if (fTextFont%10 < 2) {
2161  if (gVirtualX) gVirtualX->SetTextAngle(angle);
2162  if (gVirtualPS) gVirtualPS->SetTextAngle(angle);
2163  gPad->PaintText(x,y,text1);
2164  return 1;
2165  }
2166 
2167  Bool_t saveb = gPad->IsBatch();
2168  // Paint the text using TMathText if contains a "\"
2169  if (strstr(text1,"\\")) {
2170  TMathText tm;
2171  tm.SetTextAlign(GetTextAlign());
2172  tm.SetTextFont(GetTextFont());
2173  tm.PaintMathText(x, y, angle, size, text1);
2174  // If PDF, paint using TLatex
2175  if (gVirtualPS) {
2176  if (gVirtualPS->InheritsFrom("TPDF") ||
2177  gVirtualPS->InheritsFrom("TSVG")) {
2178  newText.ReplaceAll("\\","#");
2179  gPad->SetBatch(kTRUE);
2180  } else {
2181  return 1;
2182  }
2183  } else {
2184  return 1;
2185  };
2186  }
2187 
2188  Double_t saveSize = size;
2189  Int_t saveFont = fTextFont;
2190  if (fTextFont%10 > 2) {
2191  UInt_t w = TMath::Abs(gPad->XtoAbsPixel(gPad->GetX2()) -
2192  gPad->XtoAbsPixel(gPad->GetX1()));
2193  UInt_t h = TMath::Abs(gPad->YtoAbsPixel(gPad->GetY2()) -
2194  gPad->YtoAbsPixel(gPad->GetY1()));
2195  if (w < h)
2196  size = size/w;
2197  else
2198  size = size/h;
2199  SetTextFont(10*(saveFont/10) + 2);
2200  }
2201 
2202  Int_t length = newText.Length() ;
2203  const Char_t *text = newText.Data() ;
2204 
2205  fX=x;
2206  fY=y;
2207  x = gPad->XtoAbsPixel(x);
2208  y = gPad->YtoAbsPixel(y);
2209  fShow = kFALSE ;
2210  TLatexFormSize fs = FirstParse(angle,size,text);
2211 
2212  fOriginSize = size;
2213 
2214  // Get current line attributes.
2215  Short_t lineW = GetLineWidth();
2216  Int_t lineC = GetLineColor();
2217 
2218  TextSpec_t spec;
2219  spec.fAngle = angle;
2220  spec.fSize = size;
2221  spec.fColor = GetTextColor();
2222  spec.fFont = GetTextFont();
2223  Short_t halign = fTextAlign/10;
2224  Short_t valign = fTextAlign - 10*halign;
2225  TextSpec_t newSpec = spec;
2226  if (fError != 0) {
2227  std::cout<<"*ERROR<TLatex>: "<<fError<<std::endl;
2228  std::cout<<"==> "<<text<<std::endl;
2229  } else {
2230  fShow = kTRUE;
2231  newSpec.fSize = size;
2232 
2233  switch (valign) {
2234  case 0: y -= fs.Under() ; break;
2235  case 1: break;
2236  case 2: y += fs.Height()*0.5-fs.Under(); y++; break;
2237  case 3: y += fs.Over() ; break;
2238  }
2239  switch (halign) {
2240  case 2: x -= fs.Width()/2 ; break;
2241  case 3: x -= fs.Width() ; break;
2242  }
2243  Analyse(x,y,newSpec,text,length);
2244  }
2245 
2246  gPad->SetBatch(saveb);
2247  SetTextSize(saveSize);
2248  SetTextAngle(angle);
2249  SetTextFont(saveFont);
2250  SetTextColor(spec.fColor);
2251  SetTextAlign(valign+10*halign);
2252  SetLineWidth(lineW);
2253  SetLineColor(lineC);
2254  delete[] fTabSize;
2255  if (fError != 0) return 0;
2256  return 1;
2257 }
2258 
2259 ////////////////////////////////////////////////////////////////////////////////
2260 /// Check if the Latex syntax is correct
2261 
2263 {
2264  const Char_t *kWord1[] = {"{}^{","{}_{","^{","_{","#scale{","#color{","#font{","#sqrt{","#[]{","#{}{","#||{",
2265  "#bar{","#vec{","#dot{","#hat{","#ddot{","#acute{","#grave{","#check{","#tilde{","#slash{","#bf{","#it{","#mbox{",
2266  "\\scale{","\\color{","\\font{","\\sqrt{","\\[]{","\\{}{","\\||{","#(){","\\(){",
2267  "\\bar{","\\vec{","\\dot{","\\hat{","\\ddot{","\\acute{","\\grave{","\\check{","\\bf{","\\it{","\\mbox{"}; // check for }
2268  const Char_t *kWord2[] = {"#scale[","#color[","#font[","#sqrt[","#kern[","#lower[","\\scale[","\\color[","\\font[","\\sqrt[","\\kern[","\\lower["}; // check for ]{ + }
2269  const Char_t *kWord3[] = {"#frac{","\\frac{","#splitline{","\\splitline{"}; // check for }{ then }
2270  const Char_t *kLeft1[] = {"#left[","\\left[","#left{","\\left{","#left|","\\left|","#left(","\\left("};
2271  const Char_t *kLeft2[] = {"#[]{","#[]{","#{}{","#{}{","#||{","#||{","#(){","#(){"};
2272  const Char_t *kRight[] = {"#right]","\\right]","#right}","\\right}","#right|","\\right|","#right)","\\right)"};
2273  const Int_t lkWord1[] = {4,4,2,2,7,7,6,6,4,4,4,5,5,5,5,6,7,7,7,7,7,4,4,6,7,7,6,6,4,4,4,4,4,5,5,5,5,6,7,7,7,4,4,6};
2274  const Int_t lkWord2[] = {7,7,6,6,6,7,7,7,6,6,6,7} ;
2275  const Int_t lkWord3[] = {6,6,11,11} ;
2276  Int_t nkWord1 = 44, nkWord2 = 12, nkWord3 = 4;
2277  Int_t i,k ;
2278  Int_t nLeft1 , nRight , nOfLeft, nOfRight;
2279  Int_t lLeft1 = 6 ;
2280  Int_t lLeft2 = 4 ;
2281  Int_t lRight = 7 ;
2282  nLeft1 = nRight = 8 ;
2283  nOfLeft = nOfRight = 0 ;
2284 
2285  Char_t buf[11] ; for (i=0;i<11;i++) buf[i]=0;
2286  Bool_t opFound ;
2287  Int_t opFrac = 0;
2288  Int_t length = text.Length() ;
2289 
2290  Int_t nOfCurlyBracket, nOfKW1, nOfKW2, nOfKW3, nOfSquareCurly, nOfCurlyCurly ;
2291  Int_t nOfExtraCurly = 0 , nOfExtraSquare = 0;
2292  Int_t nOfSquareBracket = 0 ;
2293  Int_t error = 0 ;
2294  Bool_t quote1 = kFALSE , quote2 = kFALSE;
2295 
2296  // first find and replace all occurrences of "kLeft1" keyword by "kLeft2" keyword,
2297  // and all occurrences of "kRight" keyword by "}".
2298  i = 0 ;
2299  while (i < length) {
2300  // The string in 'buf' does not need to be null terminated,
2301  // we will only check with strncmp.
2302  strncpy(buf,&text[i],TMath::Min(7,length-i));
2303  opFound = kFALSE ;
2304  for (k = 0 ; k < nLeft1 ; k++) {
2305  if (strncmp(buf,kLeft1[k],lLeft1)==0) {
2306  nOfLeft++ ;
2307  i+=lLeft1 ;
2308  opFound = kTRUE ;
2309  break ;
2310  }
2311  }
2312  if (opFound) continue ;
2313 
2314  for(k=0;k<nRight;k++) {
2315  if (strncmp(buf,kRight[k],lRight)==0) {
2316  nOfRight++ ;
2317  i+=lRight ;
2318  opFound = kTRUE ;
2319  break ;
2320  }
2321  }
2322  if (!opFound) i++ ;
2323  }
2324  if (nOfLeft != nOfRight) {
2325  printf(" nOfLeft = %d, nOfRight = %d\n",nOfLeft,nOfRight) ;
2326  error = 1 ;
2327  fError = "Operators \"#left\" and \"#right\" don't match !" ;
2328  goto ERROR_END ;
2329  }
2330 
2331  for (k = 0 ; k < nLeft1 ; k++) {
2332  text.ReplaceAll(kLeft1[k],lLeft1,kLeft2[k],lLeft2) ;
2333  }
2334  for (k = 0 ; k < nRight ; k++) {
2335  text.ReplaceAll(kRight[k],lRight,"}",1) ;
2336  }
2337  length = text.Length() ;
2338 
2339  i = nOfCurlyBracket = nOfKW1 = nOfKW2 = nOfKW3 = nOfSquareCurly = nOfCurlyCurly =0 ;
2340  while (i< length){
2341  switch (text[i]) {
2342  case '"' : quote1 = !quote1 ; break ;
2343  case '\'': quote2 = !quote2 ; break ;
2344  }
2345  // The string in 'buf' does not need to be null terminated,
2346  // we will only check with strncmp
2347  strncpy(buf,&text[i],TMath::Min(11,length-i));
2348  opFound = kFALSE ;
2349 
2350  for(k=0;k<nkWord1;k++) {
2351  if (strncmp(buf,kWord1[k],lkWord1[k])==0) {
2352  nOfKW1++ ;
2353  i+=lkWord1[k] ;
2354  opFound = kTRUE ;
2355  nOfCurlyBracket++ ;
2356  break ;
2357  }
2358  }
2359  if (opFound) continue ;
2360 
2361  for(k=0;k<nkWord2;k++) {
2362  if (strncmp(buf,kWord2[k],lkWord2[k])==0) {
2363  nOfKW2++ ;
2364  i+=lkWord2[k] ;
2365  opFound = kTRUE ;
2366  nOfSquareBracket++;
2367  break ;
2368  }
2369  }
2370  if (opFound) continue ;
2371 
2372  for(k=0;k<nkWord3;k++) {
2373  if (strncmp(buf,kWord3[k],lkWord3[k])==0) {
2374  nOfKW3++ ;
2375  i+=lkWord3[k] ;
2376  opFound = kTRUE ;
2377  opFrac++ ;
2378  nOfCurlyBracket++ ;
2379  break ;
2380  }
2381  }
2382  if (opFound) continue ;
2383  if (strncmp(buf,"}{",2) == 0 && opFrac) {
2384  opFrac-- ;
2385  nOfCurlyCurly++ ;
2386  i+= 2;
2387  }
2388  else if (strncmp(buf,"]{",2) == 0 && nOfSquareBracket) {
2389  nOfSquareCurly++ ;
2390  i+= 2 ;
2391  nOfCurlyBracket++ ;
2392  nOfSquareBracket-- ;
2393  }
2394  else if (strncmp(buf,"@{",2) == 0 || strncmp(buf,"@}",2) == 0) {
2395  i+= 2 ;
2396  }
2397  else if (strncmp(buf,"@[",2) == 0 || strncmp(buf,"@]",2) == 0) {
2398  i+= 2 ;
2399  }
2400  else if (text[i] == ']' ) { // not belonging to a key word, add @ in front
2401  text.Insert(i,"@") ;
2402  length++ ;
2403  i+=2 ;
2404  nOfExtraSquare-- ;
2405  }
2406  else if (text[i] == '[' ) { // not belonging to a key word, add @ in front
2407  text.Insert(i,"@") ;
2408  length++ ;
2409  i+=2 ;
2410  nOfExtraSquare++ ;
2411  }
2412  else if (text[i] == '{' ) { // not belonging to a key word, add @ in front
2413  text.Insert(i,"@") ;
2414  length++ ;
2415  i+=2 ;
2416  nOfExtraCurly++ ;
2417  }
2418  else if (text[i] == '}' ) {
2419  if ( nOfCurlyBracket) {
2420  nOfCurlyBracket-- ;
2421  i++ ;
2422  } else { // extra }, add @ in front
2423  text.Insert(i,"@") ;
2424  length++ ;
2425  i+=2 ;
2426  nOfExtraCurly-- ;
2427  }
2428  } else {
2429  i++ ;
2430  buf[1] = 0 ;
2431  }
2432  }
2433 
2434  if (nOfKW2 != nOfSquareCurly) {
2435  error = 1 ;
2436  fError = "Invalid number of \"]{\"" ;
2437  }
2438  else if (nOfKW3 != nOfCurlyCurly) {
2439  error = 1 ;
2440  fError = "Error in syntax of \"#frac\"" ;
2441  }
2442  else if (nOfCurlyBracket < 0) {
2443  error = 1 ;
2444  fError = "Missing \"{\"" ;
2445  }
2446  else if (nOfCurlyBracket > 0) {
2447  error = 1 ;
2448  fError = "Missing \"}\"" ;
2449  }
2450  else if (nOfSquareBracket < 0) {
2451  error = 1 ;
2452  fError = "Missing \"[\"" ;
2453  }
2454  else if (nOfSquareBracket > 0) {
2455  error = 1 ;
2456  fError = "Missing \"]\"" ;
2457  }
2458 
2459  ERROR_END:
2460  return error ;
2461 }
2462 
2463 ////////////////////////////////////////////////////////////////////////////////
2464 /// First parsing of the analyse sequence
2465 
2467 {
2468  fError = 0;
2469  fTabMax = 100;
2470  fTabSize = new FormSize_t[fTabMax];
2471  // we assume less than 100 parts in one formula
2472  // we will reallocate if necessary.
2473  fPos = 0;
2474  fShow = kFALSE;
2475  fOriginSize = size;
2476 
2477  //get current line attributes
2478  Short_t lineW = GetLineWidth();
2479  Int_t lineC = GetLineColor();
2480 
2481  TextSpec_t spec;
2482  spec.fAngle = angle;
2483  if (fTextFont%10 == 3) {
2484  Double_t hw = TMath::Max((Double_t)gPad->XtoPixel(gPad->GetX2()),
2485  (Double_t)gPad->YtoPixel(gPad->GetY1()));
2486  spec.fSize = size/hw;
2487  } else {
2488  spec.fSize = size;
2489  }
2490  spec.fColor = GetTextColor();
2491  spec.fFont = GetTextFont();
2492  Short_t halign = fTextAlign/10;
2493  Short_t valign = fTextAlign - 10*halign;
2494 
2495  TLatexFormSize fs = Anal1(spec,text,strlen(text));
2496 
2497  SetTextSize(size);
2498  SetTextAngle(angle);
2499  SetTextFont(spec.fFont);
2500  SetTextColor(spec.fColor);
2501  SetTextAlign(valign+10*halign);
2502  SetLineWidth(lineW);
2503  SetLineColor(lineC);
2504  return fs;
2505 }
2506 
2507 ////////////////////////////////////////////////////////////////////////////////
2508 /// Return height of current pad in pixels
2509 
2511 {
2512  Double_t w = gPad->GetAbsWNDC()*Double_t(gPad->GetWw());
2513  Double_t h = gPad->GetAbsHNDC()*Double_t(gPad->GetWh());
2514  if (w < h)
2515  return w;
2516  else
2517  return h;
2518 }
2519 
2520 ////////////////////////////////////////////////////////////////////////////////
2521 /// Return size of the formula along X in pad coordinates
2522 
2524 {
2525  if (!gPad) return 0;
2526  TString newText = GetTitle();
2527  if( newText.Length() == 0) return 0;
2528 
2529  // The text is a TMathText.
2530  if ( newText.Contains("\\") ) {
2531  TMathText tm(0., 0., newText.Data());
2532  return tm.GetXsize();
2533  }
2534 
2535  fError = 0 ;
2536  if (CheckLatexSyntax(newText)) {
2537  std::cout<<"\n*ERROR<TLatex>: "<<fError<<std::endl;
2538  std::cout<<"==> "<<GetTitle()<<std::endl;
2539  return 0;
2540  }
2541  fError = 0 ;
2542 
2543  const Char_t *text = newText.Data() ;
2544  Double_t angle_old = GetTextAngle();
2546  SetTextAngle(angle_old);
2547  delete[] fTabSize;
2548  return TMath::Abs(gPad->AbsPixeltoX(Int_t(fs.Width())) - gPad->AbsPixeltoX(0));
2549 }
2550 
2551 ////////////////////////////////////////////////////////////////////////////////
2552 /// Return text size in pixels
2553 
2554 void TLatex::GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t angle)
2555 {
2556  if (!gPad) return;
2557  TString newText = GetTitle();
2558  if( newText.Length() == 0) return;
2559 
2560  // The text is a TMathText.
2561  if ( newText.Contains("\\") ) {
2562  TMathText tm(0., 0., newText.Data());
2563  tm.GetBoundingBox(w, h);
2564  return;
2565  }
2566 
2567  fError = 0 ;
2568  if (CheckLatexSyntax(newText)) {
2569  std::cout<<"\n*ERROR<TLatex>: "<<fError<<std::endl;
2570  std::cout<<"==> "<<GetTitle()<<std::endl;
2571  return;
2572  }
2573  fError = 0 ;
2574 
2575  if (angle) {
2576  Int_t cBoxX[4], cBoxY[4];
2577  Int_t ptx, pty;
2578  if (TestBit(kTextNDC)) {
2579  ptx = gPad->UtoPixel(fX);
2580  pty = gPad->VtoPixel(fY);
2581  } else {
2582  ptx = gPad->XtoAbsPixel(gPad->XtoPad(fX));
2583  pty = gPad->YtoAbsPixel(gPad->YtoPad(fY));
2584  }
2585  GetControlBox(ptx, pty, fTextAngle, cBoxX, cBoxY);
2586  Int_t x1 = cBoxX[0];
2587  Int_t x2 = cBoxX[0];
2588  Int_t y1 = cBoxY[0];
2589  Int_t y2 = cBoxY[0];
2590  for (Int_t i=1; i<4; i++) {
2591  if (cBoxX[i] < x1) x1 = cBoxX[i];
2592  if (cBoxX[i] > x2) x2 = cBoxX[i];
2593  if (cBoxY[i] < y1) y1 = cBoxY[i];
2594  if (cBoxY[i] > y2) y2 = cBoxY[i];
2595  }
2596  w = x2-x1;
2597  h = y2-y1;
2598  } else {
2599  const Char_t *text = newText.Data() ;
2601  delete[] fTabSize;
2602  w = (UInt_t)fs.Width();
2603  h = (UInt_t)fs.Height();
2604  }
2605 }
2606 
2607 ////////////////////////////////////////////////////////////////////////////////
2608 /// Return size of the formula along Y in pad coordinates
2609 
2611 {
2612  if (!gPad) return 0;
2613  TString newText = GetTitle();
2614  if( newText.Length() == 0) return 0;
2615 
2616  // The text is a TMathText.
2617  if ( newText.Contains("\\") ) {
2618  TMathText tm(0., 0., newText.Data());
2619  return tm.GetYsize();
2620  }
2621 
2622  fError = 0 ;
2623  if (CheckLatexSyntax(newText)) {
2624  std::cout<<"\n*ERROR<TLatex>: "<<fError<<std::endl;
2625  std::cout<<"==> "<<GetTitle()<<std::endl;
2626  return 0;
2627  }
2628  fError = 0 ;
2629 
2630  const Char_t *text = newText.Data() ;
2631  Double_t angsav = fTextAngle;
2633  fTextAngle = angsav;
2634  delete[] fTabSize;
2635  return TMath::Abs(gPad->AbsPixeltoY(Int_t(fs.Height())) - gPad->AbsPixeltoY(0));
2636 }
2637 
2638 ////////////////////////////////////////////////////////////////////////////////
2639 /// Read fs in fTabSize
2640 
2642 {
2643  fPos--;
2644  TLatexFormSize result(fTabSize[fPos].fWidth,fTabSize[fPos].fOver,fTabSize[fPos].fUnder);
2645  return result;
2646 }
2647 
2648 ////////////////////////////////////////////////////////////////////////////////
2649 /// Save fs values in array fTabSize
2650 
2652 {
2653  fTabSize[fPos].fWidth = fs->Width();
2654  fTabSize[fPos].fOver = fs->Over();
2655  fTabSize[fPos].fUnder = fs->Under();
2656  fPos++;
2657  if (fPos>=fTabMax) {
2658  // allocate more memory
2659  FormSize_t *temp = new FormSize_t[fTabMax+100];
2660  // copy array
2661  memcpy(temp,fTabSize,fTabMax*sizeof(FormSize_t));
2662  fTabMax += 100;
2663  // free previous array
2664  delete [] fTabSize;
2665  // swap pointers
2666  fTabSize = temp;
2667  }
2668 }
2669 
2670 ////////////////////////////////////////////////////////////////////////////////
2671 /// Save primitive as a C++ statement(s) on output stream out
2672 
2673 void TLatex::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
2674 {
2675  char quote = '"';
2676 
2677  if (gROOT->ClassSaved(TLatex::Class())) {
2678  out<<" ";
2679  } else {
2680  out<<" TLatex *";
2681  }
2682 
2683  TString s = GetTitle();
2684 
2685  s.ReplaceAll("\\","\\\\");
2686  s.ReplaceAll("\"","\\\"");
2687  out<<" tex = new TLatex("<<fX<<","<<fY<<","<<quote<<s.Data()<<quote<<");"<<std::endl;
2688  if (TestBit(kTextNDC)) out<<"tex->SetNDC();"<<std::endl;
2689 
2690  SaveTextAttributes(out,"tex",11,0,1,62,0.05);
2691  SaveLineAttributes(out,"tex",1,1,1);
2692 
2693  out<<" tex->Draw();"<<std::endl;
2694 }
2695 
2696 ////////////////////////////////////////////////////////////////////////////////
2697 /// Set relative size of subscripts and superscripts
2698 
2699 void TLatex::SetIndiceSize(Double_t factorSize)
2700 {
2701  fFactorSize = factorSize;
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// Set limit for text resizing of subscripts and superscripts
2706 
2707 void TLatex::SetLimitIndiceSize(Int_t limitFactorSize)
2708 {
2709  fLimitFactorSize = limitFactorSize;
2710 }
virtual void SetLineWidth(Width_t lwidth)
Set the line width.
Definition: TAttLine.h:43
Int_t fLimitFactorSize
lower bound for subscripts/superscripts size
Definition: TLatex.h:70
Bool_t fShow
! is true during the second pass (Painting)
Definition: TLatex.h:72
virtual void PaintMathText(Double_t x, Double_t y, Double_t angle, Double_t size, const char *text)
Paint text (used by Paint()).
Definition: TMathText.cxx:584
virtual void GetTextAscentDescent(UInt_t &a, UInt_t &d, const char *text) const
Return text ascent and descent for string text.
Definition: TText.cxx:523
const Double_t kPI
Definition: TLatex.cxx:21
auto * m
Definition: textangle.C:8
Double_t Log(Double_t x)
Definition: TMath.h:750
Double_t fOriginSize
Font size of the starting font.
Definition: TLatex.h:74
virtual Color_t GetTextColor() const
Return the text color.
Definition: TAttText.h:34
float Float_t
Definition: RtypesCore.h:55
virtual Short_t GetTextAlign() const
Return the text alignment.
Definition: TAttText.h:32
const char Option_t
Definition: RtypesCore.h:64
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
void Copy(TObject &text) const
Copy this text to text.
Definition: TText.cxx:107
virtual Float_t GetTextAngle() const
Return the text angle.
Definition: TAttText.h:33
Double_t Over() const
Definition: TLatex.h:63
#define gROOT
Definition: TROOT.h:405
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
Basic string class.
Definition: TString.h:131
virtual void GetControlBox(Int_t x, Int_t y, Double_t theta, Int_t cBoxX[4], Int_t cBoxY[4])
Return the text control box.
Definition: TText.cxx:423
TLatex helper struct holding the dimensions of a piece of text.
Definition: TLatex.h:31
Int_t fTabMax
! Maximum allocation for array fTabSize;
Definition: TLatex.h:75
#define f(i)
Definition: RSha256.hxx:104
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180
int Int_t
Definition: RtypesCore.h:43
void GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t angle=kFALSE)
Get the text width and height.
Definition: TMathText.cxx:486
virtual void Modify()
Change current line attributes if necessary.
Definition: TAttLine.cxx:242
Double_t fOver
Definition: TLatex.h:32
TLatex & operator=(const TLatex &)
assignment operator
Definition: TLatex.cxx:447
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
virtual Width_t GetLineWidth() const
Return the line width.
Definition: TAttLine.h:35
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
if object in a list can be deleted
Definition: TObject.h:58
Int_t PaintLatex1(Double_t x, Double_t y, Double_t angle, Double_t size, const char *text)
Drawing function.
Definition: TLatex.cxx:2143
virtual void AppendPad(Option_t *option="")
Append graphics object to current pad.
Definition: TObject.cxx:105
virtual void Modify()
Change current text attributes if necessary.
Definition: TAttText.cxx:303
TLatex * DrawLatexNDC(Double_t x, Double_t y, const char *text)
Draw this TLatex with new coordinates in NDC.
Definition: TLatex.cxx:1939
virtual void SetTextFont(Font_t tfont=62)
Set the text font.
Definition: TAttText.h:45
Double_t fSize
Definition: TLatex.h:25
static const double x2[5]
void DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, TextSpec_t spec)
Draw a line in a Latex formula.
Definition: TLatex.cxx:1949
Double_t GetYsize()
Return size of the formula along Y in pad coordinates.
Definition: TLatex.cxx:2608
Double_t x[n]
Definition: legend1.C:17
TLatexFormSize AddOver(TLatexFormSize f)
Definition: TLatex.h:54
void DrawCircle(Double_t x1, Double_t y1, Double_t r, TextSpec_t spec)
Draw an arc of ellipse in a Latex formula (right or left parenthesis)
Definition: TLatex.cxx:1969
void Class()
Definition: Class.C:29
void Copy(TAttLine &attline) const
Copy this line attributes to a new TAttLine.
Definition: TAttLine.cxx:172
virtual void SaveLineAttributes(std::ostream &out, const char *name, Int_t coldef=1, Int_t stydef=1, Int_t widdef=1)
Save line attributes as C++ statement(s) on output stream out.
Definition: TAttLine.cxx:270
virtual Float_t GetTextSize() const
Return the text size.
Definition: TAttText.h:36
TLatexFormSize Anal1(TextSpec_t spec, const Char_t *t, Int_t length)
Analyse function.
Definition: TLatex.cxx:488
const char * tab3
Definition: TXMLPlayer.cxx:124
To draw Mathematical Formula.
Definition: TLatex.h:18
virtual void Paint(Option_t *option="")
Paint.
Definition: TLatex.cxx:2029
static const double x4[22]
TLatex * DrawLatex(Double_t x, Double_t y, const char *text)
Make a copy of this object with the new parameters And copy object attributes.
Definition: TLatex.cxx:1926
Base class for several text objects.
Definition: TText.h:22
TLatex()
Default constructor.
Definition: TLatex.cxx:385
virtual void SetNDC(Bool_t isNDC=kTRUE)
Set NDC mode on if isNDC = kTRUE, off otherwise.
Definition: TText.cxx:813
static constexpr double s
Int_t CheckLatexSyntax(TString &text)
Check if the Latex syntax is correct.
Definition: TLatex.cxx:2260
constexpr Double_t Pi()
Definition: TMath.h:38
Double_t Height() const
Definition: TLatex.h:65
virtual void PaintLatex(Double_t x, Double_t y, Double_t angle, Double_t size, const char *text)
Main drawing function.
Definition: TLatex.cxx:2050
virtual void Text(Double_t x, Double_t y, const char *string)=0
void DrawParenthesis(Double_t x1, Double_t y1, Double_t r1, Double_t r2, Double_t phimin, Double_t phimax, TextSpec_t spec)
Draw an arc of ellipse in a Latex formula (right or left parenthesis)
Definition: TLatex.cxx:1998
virtual void SetTextAlign(Short_t align=11)
Set the text alignment.
Definition: TAttText.h:41
const Char_t * fError
! error code
Definition: TLatex.h:71
const char * tab2
Definition: TXMLPlayer.cxx:123
void Copy(TAttText &atttext) const
Copy this text attributes to a new TAttText.
Definition: TAttText.cxx:291
void Set(Double_t x, Double_t y1, Double_t y2)
Definition: TLatex.h:53
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition: TAttLine.h:40
Float_t fTextAngle
Text angle.
Definition: TAttText.h:21
Double_t GetHeight() const
Return height of current pad in pixels.
Definition: TLatex.cxx:2508
virtual void SavePrimitive(std::ostream &out, Option_t *option="")
Save primitive as a C++ statement(s) on output stream out.
Definition: TLatex.cxx:2671
Double_t fWidth
Definition: TLatex.h:32
ROOT::R::TRInterface & r
Definition: Object.C:4
Double_t GetXsize()
Return size of the formula along X in pad coordinates.
Definition: TLatex.cxx:2521
TLatexFormSize Readfs()
Read fs in fTabSize.
Definition: TLatex.cxx:2639
virtual void SaveTextAttributes(std::ostream &out, const char *name, Int_t alidef=12, Float_t angdef=0, Int_t coldef=1, Int_t fondef=61, Float_t sizdef=1)
Save text attributes as C++ statement(s) on output stream out.
Definition: TAttText.cxx:344
auto * a
Definition: textangle.C:12
virtual Font_t GetTextFont() const
Return the text font.
Definition: TAttText.h:35
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
virtual void SetTextAngle(Float_t tangle=0)
Set the text angle.
Definition: TAttText.h:42
Double_t fY
Y position of text (left,center,etc..)
Definition: TText.h:26
unsigned int UInt_t
Definition: RtypesCore.h:44
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:888
Ssiz_t Length() const
Definition: TString.h:405
Double_t fUnder
Definition: TLatex.h:32
TLatexFormSize Analyse(Double_t x, Double_t y, TextSpec_t spec, const Char_t *t, Int_t length)
Analyse and paint the TLatex formula.
Definition: TLatex.cxx:520
short Short_t
Definition: RtypesCore.h:37
void GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t angle=kFALSE)
Return text size in pixels.
Definition: TLatex.cxx:2552
Double_t Width() const
Definition: TLatex.h:62
The text postion is in NDC coordinates.
Definition: TLatex.h:101
Font_t fTextFont
Text font.
Definition: TAttText.h:25
TLatexFormSize FirstParse(Double_t angle, Double_t size, const Char_t *text)
First parsing of the analyse sequence.
Definition: TLatex.cxx:2464
void Savefs(TLatexFormSize *fs)
Save fs values in array fTabSize.
Definition: TLatex.cxx:2649
#define gVirtualX
Definition: TVirtualX.h:338
#define h(i)
Definition: RSha256.hxx:106
Double_t Cos(Double_t)
Definition: TMath.h:631
const Bool_t kFALSE
Definition: RtypesCore.h:90
FormSize_t * fTabSize
! array of values for the different zones
Definition: TLatex.h:73
virtual Color_t GetLineColor() const
Return the line color.
Definition: TAttLine.h:33
virtual ~TLatex()
Destructor.
Definition: TLatex.cxx:422
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
#define d(i)
Definition: RSha256.hxx:102
Double_t Exp(Double_t x)
Definition: TMath.h:717
static const double x1[5]
Int_t fPos
! Current position in array fTabSize;
Definition: TLatex.h:76
#define ClassImp(name)
Definition: Rtypes.h:361
TLatex helper class used to compute the size of a portion of a formula.
Definition: TLatex.h:39
double Double_t
Definition: RtypesCore.h:57
TText * text
Double_t y[n]
Definition: legend1.C:17
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
To draw TeX Mathematical Formula.
Definition: TMathText.h:19
void Copy(TObject &text) const
Copy this TLatex object to another TLatex.
Definition: TLatex.cxx:469
Double_t fFactorPos
! Relative position of subscripts and superscripts
Definition: TLatex.h:69
virtual void GetTextExtent(UInt_t &w, UInt_t &h, const char *text) const
Return text extent for string text.
Definition: TText.cxx:587
Binding & operator=(OUT(*fun)(void))
Mother of all ROOT objects.
Definition: TObject.h:37
TLatex helper struct holding the attributes of a piece of text.
Definition: TLatex.h:24
char Char_t
Definition: RtypesCore.h:31
TText & operator=(const TText &src)
Assignment operator.
Definition: TText.cxx:98
auto * l
Definition: textangle.C:4
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
Double_t Sin(Double_t)
Definition: TMath.h:627
Bool_t fItalic
! Currently inside italic operator
Definition: TLatex.h:77
#define snprintf
Definition: civetweb.c:1540
R__EXTERN TVirtualPS * gVirtualPS
Definition: TVirtualPS.h:81
#define gPad
Definition: TVirtualPad.h:287
virtual void SetLimitIndiceSize(Int_t limitFactorSize)
Set limit for text resizing of subscripts and superscripts.
Definition: TLatex.cxx:2705
virtual void SetTextColor(Color_t tcolor=1)
Set the text color.
Definition: TAttText.h:43
TVirtualPS is an abstract interface to Postscript, PDF, SVG.
Definition: TVirtualPS.h:30
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
Definition: TAttText.h:46
const Bool_t kTRUE
Definition: RtypesCore.h:89
Double_t Under() const
Definition: TLatex.h:64
virtual void PaintText(Double_t x, Double_t y, const char *text)
Draw this text with new coordinates.
Definition: TText.cxx:744
Double_t GetYsize(void)
Get Y size.
Definition: TMathText.cxx:527
Double_t GetXsize(void)
Get X size.
Definition: TMathText.cxx:506
Line Attributes class.
Definition: TAttLine.h:18
Double_t fFactorSize
! Relative size of subscripts and superscripts
Definition: TLatex.h:68
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
Double_t fX
X position of text (left,center,etc..)
Definition: TText.h:25
virtual void SetIndiceSize(Double_t factorSize)
Set relative size of subscripts and superscripts.
Definition: TLatex.cxx:2697
Short_t fTextAlign
Text alignment.
Definition: TAttText.h:23
static const double x3[11]
const char * Data() const
Definition: TString.h:364