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 Float_t *bb = fManager->GetBBox();
127 if (!bb)
128 return;
129
130 Float_t pmin_t = bb[ax * 2], pmax_t = bb[ax * 2 + 1];
131 if (pmax_t <= pmin_t)
132 return;
133
134 // The tick step comes from the true range and only the extent from the
135 // widened one. A step derived from the widened range can jump to a coarser
136 // round number and leave fewer labels inside the view.
137 Float_t center = 0.5f * (pmin_t + pmax_t);
138 Float_t half = 0.5f * (pmax_t - pmin_t) * fRangeFactor;
139 Float_t pmin = center - half;
140 Float_t pmax = center + half;
141
142 // Decoded as in TEveProjectionAxes: primary = n / 100, secondary = n % 100.
144 Int_t n2a = fNdivisions - n1a * 100;
145 Int_t bn1, bn2;
146 Double_t bw1, bw2;
147 Double_t bl1 = 0, bh1 = 0, bl2 = 0, bh2 = 0;
148
149 if (fLabMode == kValue) {
150 // Round numbers in the original space, placed where the projection puts
151 // them. Their screen spacing is uneven under a non-linear projection.
152 Float_t v1 = proj->GetValForScreenPos(ax, pmin_t);
153 Float_t v2 = proj->GetValForScreenPos(ax, pmax_t);
154 if (v2 <= v1)
155 return;
156
157 // Step from the true range (see above), extent from the widened one.
158 THLimitsFinder::Optimize(v1, v2, n1a, bl1, bh1, bn1, bw1);
159 THLimitsFinder::Optimize(bl1, bl1 + bw1, n2a, bl2, bh2, bn2, bw2);
160 if (bw1 <= 0)
161 return;
162
163 Double_t vc = 0.5 * (v1 + v2), vh = 0.5 * (v2 - v1) * fRangeFactor;
164 Int_t k1 = TMath::FloorNint((vc - vh - bl1) / bw1);
165 Int_t k2 = TMath::CeilNint((vc + vh - bl1) / bw1);
166
167 // Cached for the cheap per-tick form of GetScreenVal().
168 REveVector dirVec;
169 proj->SetDirectionalVector(ax, dirVec);
170 REveVector oCenter;
171 proj->GetOrthogonalCenter(ax, oCenter);
172
173 for (Int_t l = k1; l <= k2; ++l) {
174 Double_t v = bl1 + l * bw1;
175 Tick_t major;
176 major.fPos = proj->GetScreenVal(ax, v);
177 major.fLabel = FormatTickLabel(v, bw1);
178 major.fMajor = kTRUE;
179 fTicks[ax].push_back(major);
180
181 for (Int_t k = 1; k < bn2; ++k) {
182 Tick_t minor;
183 minor.fPos = proj->GetScreenVal(ax, v + k * bw2, dirVec, oCenter);
184 minor.fMajor = kFALSE;
185 fTicks[ax].push_back(minor);
186 }
187 }
188 } else {
189 // Even spacing in projected space; the labels are then irregular values.
190 // Step from the true range here too, for the same reason.
191 THLimitsFinder::Optimize(pmin_t, pmax_t, n1a, bl1, bh1, bn1, bw1);
192 THLimitsFinder::Optimize(bl1, bl1 + bw1, n2a, bl2, bh2, bn2, bw2);
193 if (bw1 <= 0)
194 return;
195
196 Int_t k1 = TMath::CeilNint(pmin / bw1);
197 Int_t k2 = TMath::FloorNint(pmax / bw1);
198
199 for (Int_t l = k1; l <= k2; ++l) {
200 Double_t p = l * bw1;
201
202 Tick_t major;
203 major.fPos = p;
204 major.fLabel = FormatTickLabel(proj->GetValForScreenPos(ax, p), bw1);
205 major.fMajor = kTRUE;
206 fTicks[ax].push_back(major);
207
208 for (Int_t k = 1; k < bn2; ++k) {
209 Double_t pm = p + k * bw2;
210 if (pm > pmax)
211 break;
212 Tick_t minor;
213 minor.fPos = pm;
214 minor.fMajor = kFALSE;
215 fTicks[ax].push_back(minor);
216 }
217 }
218 }
219}
220
221////////////////////////////////////////////////////////////////////////////////
222/// Stream style, mode and the tick sets. Positions are in projected
223/// coordinates; the client maps them to screen with its own camera.
224
225Int_t REveProjectionAxis::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
226{
227 Int_t ret = REveText::WriteCoreJson(j, rnr_offset);
228
229 j["fLabMode"] = (int)fLabMode;
230 j["fAxesMode"] = (int)fAxesMode;
231 j["fUseFgColor"] = fUseFgColor;
232 j["fDrawCenter"] = fDrawCenter;
233 j["fDrawOrigin"] = fDrawOrigin;
234
235 for (int ax = 0; ax < 2; ++ax) {
236 nlohmann::json pos = nlohmann::json::array();
237 nlohmann::json lab = nlohmann::json::array();
238 nlohmann::json maj = nlohmann::json::array();
239 for (auto &t : fTicks[ax]) {
240 pos.push_back(t.fPos);
241 lab.push_back(t.fLabel);
242 maj.push_back(t.fMajor);
243 }
244 std::string key = (ax == 0) ? "H" : "V";
245 j["fTickPos" + key] = pos;
246 j["fTickLab" + key] = lab;
247 j["fTickMaj" + key] = maj;
248 }
249
250 return ret;
251}
252
253////////////////////////////////////////////////////////////////////////////////
254/// Render data. The ticks travel as JSON above, since the labels are strings;
255/// this only names the client-side factory.
256
258{
259 fRenderData = std::make_unique<REveRenderData>("makeProjectionAxis");
261 fRenderData->PushV(0.f, 0.f, 0.f); // keep the buffer non-empty
262}
263
264////////////////////////////////////////////////////////////////////////////////
265/// Attach a text element that shows the current distortion. Only its text is
266/// rewritten, so it can sit in any scene. The label is not owned and its
267/// lifetime is not tracked.
268
274
275////////////////////////////////////////////////////////////////////////////////
276/// Forget the projection manager when it is destroyed, then clear any click
277/// target as REveText does.
278
280{
281 if (fManager && au == fManager)
282 fManager = nullptr;
284}
285
286////////////////////////////////////////////////////////////////////////////////
287/// Rewrite the read-out. Shown as distortion * 1000, the same scaling
288/// REveProjectionManager uses in its own name.
289
291{
292 if (!fDistLabel || !fManager)
293 return;
295 if (!proj)
296 return;
297
298 fDistLabel->SetText(TString::Format("%.1f", proj->GetDistortion() * 1000).Data());
299}
#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.
virtual void BuildRenderData()
Write transformation Matrix to render data.
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.
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
Float_t * GetBBox()
Definition TAttBBox.h:55
Float_t * AssertBBox()
Definition TAttBBox.h:56
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