Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
REveProjectionAxis.cxx
Go to the documentation of this file.
1// @(#)root/eve7:$Id$
2// Authors: Matevz Tadel & Alja Mrak-Tadel
3
4/*************************************************************************
5 * Copyright (C) 1995-2019, 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
16
17#include "THLimitsFinder.h"
18#include "TMath.h"
19#include "TString.h"
20
21#include <cmath>
22
23using namespace ROOT::Experimental;
24
25/** \class REveProjectionAxis
26\ingroup REve
27Scales and tick labels for a projected view, the REve counterpart of
28TEveProjectionAxes.
29
30In kValue mode the ticks sit at round numbers in the original space and are
31placed at their projected positions, so under a non-linear projection their
32screen spacing is uneven. The projection exists only on the server, so the
33mapping from original to projected coordinates is done here and the ticks are
34streamed in projected coordinates. The client maps them to the screen, which
35for the orthographic camera of a projected view is affine.
36
37The tick set covers fRangeFactor times the projection manager's extent. The
38client discards ticks outside the view and labels that overlap, so zooming and
39panning need no server round trip. Ticks are recomputed only when the
40projection or the scene extent changes.
41
42The projection manager is held as an aunt and is not owned.
43
44Inherits REveText for its style: font, size, hinting, weight and text colour
45apply to the labels, and the line colour to the ticks. fText, fPosition,
46fMode, fResizable, the alignment and the frame are not used.
47*/
48
49namespace {
50
51/// Format a tick value with enough decimals to separate ticks `step` apart;
52/// exponent form outside [1e-4, 1e5).
53std::string FormatTickLabel(Double_t v, Double_t step)
54{
55 if (std::fabs(v) < 1e-12)
56 return "0";
57
58 Int_t nd = 0;
59 if (step > 0.0 && step < 1.0)
60 nd = TMath::Min(6, (Int_t)std::ceil(-std::log10(step)));
61
62 // Very large or very small numbers read better in exponent form.
63 Double_t a = std::fabs(v);
64 if (a >= 1e5 || a < 1e-4)
65 return TString::Format("%.1e", v).Data();
66
67 return TString::Format("%.*f", nd, v).Data();
68}
69
70} // namespace
71
72////////////////////////////////////////////////////////////////////////////////
73/// Constructor. Registers as a niece of `m`. ProjectChildren() visits the
74/// nieces but reprojects only REveProjected ones, so the axis is skipped.
75
76REveProjectionAxis::REveProjectionAxis(REveProjectionManager *m, const Text_t *n, const Text_t *t)
77 : REveText(n, t), fManager(m)
78{
79 // Style defaults for tick labels rather than a free-standing text box.
80 SetMode(1); // not read by makeProjectionAxis
81 // Larger and slightly bolder than the REveText default, for labels a few
82 // pixels tall in a small projected pane.
83 SetFontSize(0.028f);
84 SetFontWeight(0.06f);
87
88 if (fManager)
89 fManager->AddNiece(this);
90
92}
93
94////////////////////////////////////////////////////////////////////////////////
95/// Destructor. The aunt link is dropped by REveElement's own cleanup, which
96/// calls RemoveNieceInternal() on every aunt, so nothing to do here.
97
99
100////////////////////////////////////////////////////////////////////////////////
101/// Recompute both tick sets. Call after the projection or the scene extent
102/// changes; camera motion needs no update.
103
110
111////////////////////////////////////////////////////////////////////////////////
112/// Build the tick set for one screen axis, 0 horizontal and 1 vertical. The
113/// range is the projection manager's bounding box widened by fRangeFactor.
114
116{
117 fTicks[ax].clear();
118
119 if (!fManager)
120 return;
122 if (!proj)
123 return;
124
126 return;
127
128 Float_t pmin_t = fManager->GetBBoxMin()[ax], pmax_t = fManager->GetBBoxMax()[ax];
129 if (pmax_t <= pmin_t)
130 return;
131
132 // The tick step comes from the true range and only the extent from the
133 // widened one. A step derived from the widened range can jump to a coarser
134 // round number and leave fewer labels inside the view.
135 Float_t center = 0.5f * (pmin_t + pmax_t);
136 Float_t half = 0.5f * (pmax_t - pmin_t) * fRangeFactor;
137 Float_t pmin = center - half;
138 Float_t pmax = center + half;
139
140 // Decoded as in TEveProjectionAxes: primary = n / 100, secondary = n % 100.
142 Int_t n2a = fNdivisions - n1a * 100;
143 Int_t bn1, bn2;
144 Double_t bw1, bw2;
145 Double_t bl1 = 0, bh1 = 0, bl2 = 0, bh2 = 0;
146
147 if (fLabMode == kValue) {
148 // Round numbers in the original space, placed where the projection puts
149 // them. Their screen spacing is uneven under a non-linear projection.
150 Float_t v1 = proj->GetValForScreenPos(ax, pmin_t);
151 Float_t v2 = proj->GetValForScreenPos(ax, pmax_t);
152 if (v2 <= v1)
153 return;
154
155 // Step from the true range (see above), extent from the widened one.
156 THLimitsFinder::Optimize(v1, v2, n1a, bl1, bh1, bn1, bw1);
157 THLimitsFinder::Optimize(bl1, bl1 + bw1, n2a, bl2, bh2, bn2, bw2);
158 if (bw1 <= 0)
159 return;
160
161 Double_t vc = 0.5 * (v1 + v2), vh = 0.5 * (v2 - v1) * fRangeFactor;
162 Int_t k1 = TMath::FloorNint((vc - vh - bl1) / bw1);
163 Int_t k2 = TMath::CeilNint((vc + vh - bl1) / bw1);
164
165 // Cached for the cheap per-tick form of GetScreenVal().
166 REveVector dirVec;
167 proj->SetDirectionalVector(ax, dirVec);
168 REveVector oCenter;
169 proj->GetOrthogonalCenter(ax, oCenter);
170
171 for (Int_t l = k1; l <= k2; ++l) {
172 Double_t v = bl1 + l * bw1;
173 Tick_t major;
174 major.fPos = proj->GetScreenVal(ax, v);
175 major.fLabel = FormatTickLabel(v, bw1);
176 major.fMajor = kTRUE;
177 fTicks[ax].push_back(major);
178
179 for (Int_t k = 1; k < bn2; ++k) {
180 Tick_t minor;
181 minor.fPos = proj->GetScreenVal(ax, v + k * bw2, dirVec, oCenter);
182 minor.fMajor = kFALSE;
183 fTicks[ax].push_back(minor);
184 }
185 }
186 } else {
187 // Even spacing in projected space; the labels are then irregular values.
188 // Step from the true range here too, for the same reason.
189 THLimitsFinder::Optimize(pmin_t, pmax_t, n1a, bl1, bh1, bn1, bw1);
190 THLimitsFinder::Optimize(bl1, bl1 + bw1, n2a, bl2, bh2, bn2, bw2);
191 if (bw1 <= 0)
192 return;
193
194 Int_t k1 = TMath::CeilNint(pmin / bw1);
195 Int_t k2 = TMath::FloorNint(pmax / bw1);
196
197 for (Int_t l = k1; l <= k2; ++l) {
198 Double_t p = l * bw1;
199
200 Tick_t major;
201 major.fPos = p;
202 major.fLabel = FormatTickLabel(proj->GetValForScreenPos(ax, p), bw1);
203 major.fMajor = kTRUE;
204 fTicks[ax].push_back(major);
205
206 for (Int_t k = 1; k < bn2; ++k) {
207 Double_t pm = p + k * bw2;
208 if (pm > pmax)
209 break;
210 Tick_t minor;
211 minor.fPos = pm;
212 minor.fMajor = kFALSE;
213 fTicks[ax].push_back(minor);
214 }
215 }
216 }
217}
218
219////////////////////////////////////////////////////////////////////////////////
220/// Stream style, mode and the tick sets. Positions are in projected
221/// coordinates; the client maps them to screen with its own camera.
222
223Int_t REveProjectionAxis::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
224{
225 Int_t ret = REveText::WriteCoreJson(j, rnr_offset);
226
227 j["fLabMode"] = (int)fLabMode;
228 j["fAxesMode"] = (int)fAxesMode;
229 j["fUseFgColor"] = fUseFgColor;
230 j["fDrawCenter"] = fDrawCenter;
231 j["fDrawOrigin"] = fDrawOrigin;
232
233 for (int ax = 0; ax < 2; ++ax) {
234 nlohmann::json pos = nlohmann::json::array();
235 nlohmann::json lab = nlohmann::json::array();
236 nlohmann::json maj = nlohmann::json::array();
237 for (auto &t : fTicks[ax]) {
238 pos.push_back(t.fPos);
239 lab.push_back(t.fLabel);
240 maj.push_back(t.fMajor);
241 }
242 std::string key = (ax == 0) ? "H" : "V";
243 j["fTickPos" + key] = pos;
244 j["fTickLab" + key] = lab;
245 j["fTickMaj" + key] = maj;
246 }
247
248 return ret;
249}
250
251////////////////////////////////////////////////////////////////////////////////
252/// Render data. The ticks travel as JSON above, since the labels are strings;
253/// this only names the client-side factory.
254
256{
257 fRenderData = std::make_unique<REveRenderData>("makeProjectionAxis");
259 fRenderData->PushV(0.f, 0.f, 0.f); // keep the buffer non-empty
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// Attach a text element that shows the current distortion. Only its text is
264/// rewritten, so it can sit in any scene. The label is not owned and its
265/// lifetime is not tracked.
266
272
273////////////////////////////////////////////////////////////////////////////////
274/// Forget the projection manager when it is destroyed, then clear any click
275/// target as REveText does.
276
278{
279 if (fManager && au == fManager)
280 fManager = nullptr;
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// Follow the projection manager: its box and distortion set the ticks and the
286/// distortion read-out.
287
289{
290 if (au != fManager)
291 return;
292 UpdateTicks();
294}
295
296////////////////////////////////////////////////////////////////////////////////
297/// Rewrite the read-out. Shown as distortion * 1000, the same scaling
298/// REveProjectionManager uses in its own name.
299
301{
302 if (!fDistLabel || !fManager)
303 return;
305 if (!proj)
306 return;
307
308 fDistLabel->SetText(TString::Format("%.1f", proj->GetDistortion() * 1000).Data());
309}
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
char Text_t
General string (char)
Definition RtypesCore.h:77
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
winID h TVirtualViewer3D TVirtualGLPainter p
virtual void AddNiece(REveElement *el)
std::unique_ptr< REveRenderData > fRenderData
! Vertex / normal / triangle index information for rendering.
const REveVector & GetBBoxMax() const
EBBoxState AssertBBox()
Compute the bounding box if it is invalid, and return its state.
const REveVector & GetBBoxMin() const
virtual void BuildRenderData()
Build fRenderData, what the client draws.
void RemoveAunt(REveAunt *au) override
Forget the projection manager when it is destroyed, then clear any click target as REveText does.
std::vector< Tick_t > fTicks[2]
! computed ticks, [0] horizontal, [1] vertical
void BuildRenderData() override
Render data.
REveText * fDistLabel
! optional read-out of the distortion, not owned
REveProjectionManager * fManager
! held as an aunt, not owned
Float_t fRangeFactor
tick range as a multiple of the manager's bbox extent, about its centre
void UpdateDistortionLabel()
Rewrite the read-out.
Bool_t fUseFgColor
Take the viewer's foreground colour instead of fTextColor/fLineColor, so the axis stays legible when ...
void SetDistortionLabel(REveText *t)
Attach a text element that shows the current distortion.
Int_t fNdivisions
Primary divisions * 100 + secondary divisions, decoded as TEveProjectionAxes does,...
void UpdateTicks()
Recompute both tick sets.
void BuildTicks(Int_t ax)
Build the tick set for one screen axis, 0 horizontal and 1 vertical.
Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override
Stream style, mode and the tick sets.
void AuntChanged(REveAunt *au) override
Follow the projection manager: its box and distortion set the ticks and the distortion read-out.
REveProjectionManager Manager class for steering of projections and managing projected objects.
REveProjection Base for specific classes that implement non-linear projections.
virtual Float_t GetValForScreenPos(Int_t ax, Float_t value)
Inverse projection.
virtual Float_t GetScreenVal(Int_t ax, Float_t value)
Project point on given axis and return projected value.
REveVector GetOrthogonalCenter(int idx, REveVector &out)
Get center ortogonal to given axis index.
virtual void SetDirectionalVector(Int_t screenAxis, REveVector &vec)
Get vector for axis in a projected space.
void SetTextAlign(Int_t h, Int_t v)
Definition REveText.hxx:95
void SetMode(Int_t mode)
Definition REveText.hxx:85
void SetFontWeight(Float_t w)
Definition REveText.hxx:107
void SetText(const std::string &text)
Definition REveText.hxx:76
Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override
Fill core part of JSON representation.
Definition REveText.cxx:74
void RemoveAunt(REveAunt *au) override
Clear the click action when the click target is destroyed, so the button does not keep an id that may...
Definition REveText.cxx:63
void SetFontSize(float size)
Definition REveText.hxx:82
static void Optimize(Double_t A1, Double_t A2, Int_t nold, Double_t &BinLow, Double_t &BinHigh, Int_t &nbins, Double_t &BWID, Option_t *option="")
Static function to compute reasonable axis limits.
const char * Data() const
Definition TString.h:385
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2460
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100
Int_t FloorNint(Double_t x)
Returns the nearest integer of TMath::Floor(x).
Definition TMath.h:699
Int_t CeilNint(Double_t x)
Returns the nearest integer of TMath::Ceil(x).
Definition TMath.h:687
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
One tick: where it lands in projected space, what to write, and whether it is a labelled (major) tick...
Float_t fPos
position along the axis, in projected coordinates
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4