Logo ROOT  
Reference Guide
REvePolygonSetProjected.cxx
Go to the documentation of this file.
1// @(#)root/eve7:$Id$
2// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007
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
13#include <ROOT/REveGeoShape.hxx>
15#include <ROOT/REveGluTess.hxx>
17
18#include "TBuffer3D.h"
19#include "TBuffer3DTypes.h"
20
21#include "json.hpp"
22#include <cassert>
23
24using namespace ROOT::Experimental;
25namespace REX = ROOT::Experimental;
26
27namespace
28{
29 struct Seg_t
30 {
31 // Helper class for building 2D polygons from TBuffer3D.
32 Int_t fV1;
33 Int_t fV2;
34
35 Seg_t(Int_t i1=-1, Int_t i2=-1) : fV1(i1), fV2(i2) {}
36 };
37
38 typedef std::list<Seg_t> LSeg_t;
39}
40
41/** \class REvePolygonSetProjected
42\ingroup REve
43A set of projected polygons.
44Used for storage of projected geometrical shapes.
45
46Internal struct Polygon_t holds only indices into the master vertex
47array in REvePolygonSetProjected.
48*/
49
50////////////////////////////////////////////////////////////////////////////////
51/// Constructor.
52
53REvePolygonSetProjected::REvePolygonSetProjected(const std::string &n, const std::string &t) :
54 REveShape(n, t),
55 fBuff(),
56 fPnts()
57{
58}
59
60////////////////////////////////////////////////////////////////////////////////
61/// Destructor.
62
64{
65 fPols.clear();
66}
67
68////////////////////////////////////////////////////////////////////////////////
69/// Fill core part of JSON representation.
70
72{
73 Int_t ret = REveElement::WriteCoreJson(j, rnr_offset);
74
75 j["fNPnts"] = fPnts.size();
76
77 return ret;
78}
79
80////////////////////////////////////////////////////////////////////////////////
81/// Crates representation for rendering.
82/// This is complicated as we need to:
83/// - generate outlines;
84/// - convert polygons to triangles.
85/// ??? Should we check if polygons are front facing? It was not done in old EVE,
86/// just GL_FRONT_AND_BACK was used on top of gluTess.
87
89{
90 fRenderData = std::make_unique<REveRenderData>("makePolygonSetProjected", 3 * fPnts.size());
91
92 Int_t n_pols = fPols.size();
93 Int_t n_poly_info = 0;
94 for (auto &p : fPols) n_poly_info += 1 + p.NPoints();
95
96 std::vector<Double_t> verts;
97 verts.reserve(3 * fPnts.size());
98 std::vector<Int_t> polys;
99 polys.reserve(n_poly_info);
100
101 for (auto &p : fPols)
102 {
103 polys.emplace_back(p.NPoints());
104 polys.insert(polys.end(), p.fPnts.begin(), p.fPnts.end());
105 }
106
107 for (unsigned i = 0; i < fPnts.size(); ++i)
108 {
109 verts.push_back(fPnts[i].fX);
110 verts.push_back(fPnts[i].fY);
111 verts.push_back(fPnts[i].fZ);
112 fRenderData->PushV(fPnts[i]);
113 }
114
115 Int_t n_trings = 0;
116 {
118
119 tc.ProcessData(verts, polys, n_pols);
120
121 polys.swap(tc.RefPolyDesc());
122 n_trings = tc.GetNTrianlges();
123 }
124
125 // Calculate size of index buffer.
126 Int_t n_idxbuff = 2 + 3 * n_trings + n_pols + n_poly_info;
127 fRenderData->Reserve(0,0,n_idxbuff);
128
129 assert(n_trings * 4 == (int)polys.size());
130
131 // Export triangles.
133 fRenderData->PushI(n_trings);
134 for (int i = 0; i < n_trings; ++i)
135 {
136 fRenderData->PushI(&polys[i*4 + 1], 3);
137 }
138
139 assert (fRenderData->SizeI() == 2 + 3 * n_trings);
140
141 // Export outlines.
142 for (auto &p : fPols)
143 {
145 fRenderData->PushI(p.NPoints());
146 fRenderData->PushI(p.fPnts);
147 }
148
149 assert (fRenderData->SizeI() == n_idxbuff);
150}
151
152////////////////////////////////////////////////////////////////////////////////
153/// Override of virtual method from TAttBBox.
154
156{
157 if (fPnts.size() > 0) {
158 BBoxInit();
159 for (unsigned pi = 0; pi < fPnts.size(); ++pi)
160 BBoxCheckPoint(fPnts[pi].fX, fPnts[pi].fY, fPnts[pi].fZ);
161 } else {
162 BBoxZero();
163 }
164}
165
166////////////////////////////////////////////////////////////////////////////////
167/// This is virtual method from base-class REveProjected.
168
170 REveProjectable* model)
171{
173
174 REveGeoShape* gre = dynamic_cast<REveGeoShape*>(model);
175 fBuff = gre->MakeBuffer3D();
176 CopyVizParams(gre);
177}
178
179////////////////////////////////////////////////////////////////////////////////
180/// Set depth (z-coordinate) of the projected points.
181
183{
184 SetDepthCommon(d, this, fBBox);
185
186 for (unsigned i = 0; i < fPnts.size(); ++i)
187 fPnts[i].fZ = fDepth;
188}
189
190////////////////////////////////////////////////////////////////////////////////
191/// This is virtual method from base-class REveProjected.
192
194{
195 if (!fBuff) return;
196
197 // drop polygons and projected/reduced points
198 fPols.clear();
200}
201
202////////////////////////////////////////////////////////////////////////////////
203/// Compare the two segments and check if the first index of first segment is starting.
204
206{
207 Int_t v0 = fBuff->fSegs[3*s0 + 1];
208 Int_t v2 = fBuff->fSegs[3*s1 + 1];
209 Int_t v3 = fBuff->fSegs[3*s1 + 2];
210 return v0 != v2 && v0 != v3;
211}
212
213////////////////////////////////////////////////////////////////////////////////
214/// Project and reduce buffer points.
215
217{
218 REveProjection* projection = fManager->GetProjection();
219
220 Int_t buffN = fBuff->NbPnts();
221 std::vector<REveVector> pnts; pnts.resize(buffN);
222 for (Int_t i = 0; i < buffN; ++i)
223 {
224 pnts[i].Set(fBuff->fPnts[3*i],fBuff->fPnts[3*i+1], fBuff->fPnts[3*i+2]);
225 projection->ProjectPoint(pnts[i].fX, pnts[i].fY, pnts[i].fZ, 0,
227 }
228
229 int npoints = 0;
230 std::vector<Int_t> idxMap;
231 idxMap.resize(buffN);
232
233 std::vector<int> ra;
234 ra.resize(buffN); // list of reduced vertices
235 for (UInt_t v = 0; v < (UInt_t)buffN; ++v)
236 {
237 idxMap[v] = -1;
238 for (Int_t k = 0; k < npoints; ++k)
239 {
240 if (pnts[v].SquareDistance(pnts[ra[k]]) < REveProjection::fgEpsSqr)
241 {
242 idxMap[v] = k;
243 break;
244 }
245 }
246 // have not found a point inside epsilon, add new point in scaled array
247 if (idxMap[v] == -1)
248 {
249 idxMap[v] = npoints;
250 ra[npoints] = v;
251 ++npoints;
252 }
253 }
254
255 // write the array of scaled points
256 fPnts.resize(npoints);
257 for (Int_t idx = 0; idx < npoints; ++idx)
258 {
259 Int_t i = ra[idx];
260 projection->ProjectPoint(pnts[i].fX, pnts[i].fY, pnts[i].fZ, fDepth,
262 fPnts[idx].Set(pnts[i]);
263 }
264 // printf("reduced %d points of %d\n", fNPnts, N);
265
266 return idxMap;
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Check if polygon has dimensions above REveProjection::fgEps and add it
271/// to a list if it is not a duplicate.
272
274{
275 if (pp.size() <= 2) return 0;
276
277 Float_t bbox[4] = { 1e6, -1e6, 1e6, -1e6 };
278 for (auto &&idx: pp)
279 {
280 if (fPnts[idx].fX < bbox[0]) bbox[0] = fPnts[idx].fX;
281 if (fPnts[idx].fX > bbox[1]) bbox[1] = fPnts[idx].fX;
282
283 if (fPnts[idx].fY < bbox[2]) bbox[2] = fPnts[idx].fY;
284 if (fPnts[idx].fY > bbox[3]) bbox[3] = fPnts[idx].fY;
285 }
287 if ((bbox[1]-bbox[0]) < eps || (bbox[3]-bbox[2]) < eps) return 0;
288
289 // Duplication
290 for (auto &&refP : pols)
291 {
292 if ((Int_t) pp.size() != refP.NPoints())
293 continue;
294
295 Int_t start_idx = refP.FindPoint(pp.front());
296 if (start_idx < 0)
297 continue;
298 if (++start_idx >= refP.NPoints()) start_idx = 0;
299
300 // Same orientation duplicate
301 {
302 auto u = ++pp.begin();
303 Int_t pidx = start_idx;
304 while (u != pp.end())
305 {
306 if ((*u) != refP.fPnts[pidx])
307 break;
308 ++u;
309 if (++pidx >= refP.NPoints()) pidx = 0;
310 }
311 if (u == pp.end()) return 0;
312 }
313 // Inverse orientation duplicate
314 {
315 auto u = --pp.end();
316 Int_t pidx = start_idx;
317 while (u != pp.begin())
318 {
319 if ((*u) != refP.fPnts[pidx])
320 break;
321 --u;
322 if (++pidx >= refP.NPoints()) pidx = 0;
323 }
324 if (u == pp.begin()) return 0;
325 }
326 }
327
328 std::vector<int> pv(pp.size(), 0);
329 int count = 0;
330 for (auto &&u : pp) {
331 pv[count++] = u;
332 }
333
334 pols.emplace_back(std::move(pv));
335
336 return (bbox[1]-bbox[0]) * (bbox[3]-bbox[2]);
337}
338
339////////////////////////////////////////////////////////////////////////////////
340/// Build polygons from list of buffer polygons.
341
343{
344 REveProjection* projection = fManager->GetProjection();
345 Int_t *bpols = fBuff->fPols;
346 Float_t surf = 0; // surface of projected polygons
347 for (UInt_t pi = 0; pi < fBuff->NbPols(); ++pi)
348 {
349 std::list<Int_t> pp; // points in current polygon
350 UInt_t segN = bpols[1];
351 Int_t *seg = &bpols[2];
352 // start idx in the fist segment depends of second segment
353 Int_t tail, head;
354 if (IsFirstIdxHead(seg[0], seg[1]))
355 {
356 head = idxMap[fBuff->fSegs[3*seg[0] + 1]];
357 tail = idxMap[fBuff->fSegs[3*seg[0] + 2]];
358 }
359 else
360 {
361 head = idxMap[fBuff->fSegs[3*seg[0] + 2]];
362 tail = idxMap[fBuff->fSegs[3*seg[0] + 1]];
363 }
364 pp.emplace_back(head);
365 // printf("start idx head %d, tail %d\n", head, tail);
366 LSeg_t segs;
367 for (UInt_t s = 1; s < segN; ++s)
368 segs.emplace_back(fBuff->fSegs[3*seg[s] + 1],fBuff->fSegs[3*seg[s] + 2]);
369
370 for (auto &it: segs)
371 {
372 Int_t mv1 = idxMap[it.fV1];
373 Int_t mv2 = idxMap[it.fV2];
374
375 if ( ! projection->AcceptSegment(fPnts[mv1], fPnts[mv2], REveProjection::fgEps))
376 {
377 pp.clear();
378 break;
379 }
380 if (tail != pp.back()) pp.push_back(tail);
381 tail = (mv1 == tail) ? mv2 : mv1;
382 }
383
384 if ( ! pp.empty())
385 {
386 // DirectDraw() implementation: last and first vertices should not be equal
387 if (pp.front() == pp.back()) pp.pop_front();
388 surf += AddPolygon(pp, fPolsBP);
389 }
390 bpols += (segN+2);
391 }
392 return surf;
393}
394
395////////////////////////////////////////////////////////////////////////////////
396/// Build polygons from the set of buffer segments.
397/// First creates a segment pool according to reduced and projected points
398/// and then build polygons from the pool.
399
401{
402 LSeg_t segs;
403 Float_t surf = 0; // surface of projected polygons
404 REveProjection *projection = fManager->GetProjection();
405 for (UInt_t s = 0; s < fBuff->NbSegs(); ++s)
406 {
407 Bool_t duplicate = kFALSE;
408 Int_t vo1, vo2; // idx from fBuff segment
409 Int_t vor1, vor2; // mapped idx
410 vo1 = fBuff->fSegs[3*s + 1];
411 vo2 = fBuff->fSegs[3*s + 2]; //... skip color info
412 vor1 = idxMap[vo1];
413 vor2 = idxMap[vo2];
414 if (vor1 == vor2) continue;
415 // check duplicate
416 for (auto &seg: segs)
417 {
418 Int_t vv1 = seg.fV1;
419 Int_t vv2 = seg.fV2;
420 if((vv1 == vor1 && vv2 == vor2) || (vv1 == vor2 && vv2 == vor1))
421 {
422 duplicate = kTRUE;
423 continue;
424 }
425 }
426 if (duplicate == kFALSE && projection->AcceptSegment(fPnts[vor1], fPnts[vor2], REveProjection::fgEps))
427 segs.emplace_back(vor1, vor2);
428 }
429
430 while (!segs.empty())
431 {
432 std::list<Int_t> pp; // points in current polygon
433 pp.push_back(segs.front().fV1);
434 Int_t tail = segs.front().fV2;
435 segs.pop_front();
436 Bool_t match = kTRUE;
437 while (match && ! segs.empty())
438 {
439 for (auto k = segs.begin(); k != segs.end(); ++k)
440 {
441 Int_t cv1 = (*k).fV1;
442 Int_t cv2 = (*k).fV2;
443 if (cv1 == tail || cv2 == tail)
444 {
445 pp.emplace_back(tail);
446 tail = (cv1 == tail) ? cv2 : cv1;
447 segs.erase(k);
448 match = kTRUE;
449 break;
450 }
451 else
452 {
453 match = kFALSE;
454 }
455 } // end for loop in the segment pool
456 if (tail == pp.front())
457 break;
458 }
459 surf += AddPolygon(pp, fPolsBS);
460 }
461 return surf;
462}
463
464////////////////////////////////////////////////////////////////////////////////
465/// Project current buffer.
466
468{
469 // create map from original to projected and reduced point needed only for geometry
470 auto idxMap = ProjectAndReducePoints();
471
473 switch (mode) {
475 MakePolygonsFromBP(idxMap);
476 fPolsBP.swap(fPols);
477 break;
478 }
480 MakePolygonsFromBS(idxMap);
481 fPolsBS.swap(fPols);
482 break;
483 }
485 // take projection with largest surface
486 Float_t surfBP = MakePolygonsFromBP(idxMap);
487 Float_t surfBS = MakePolygonsFromBS(idxMap);
488 if (surfBS < surfBP) {
489 fPolsBP.swap(fPols);
490 fPolsBS.clear();
491 } else {
492 fPolsBS.swap(fPols);
493 fPolsBP.clear();
494 }
495 break;
496 }
497 default: break;
498 }
499
500 ResetBBox();
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// Calculate XY surface of a polygon.
505
507{
508 Float_t surf = 0;
509 Int_t nPnts = p.NPoints();
510 for (Int_t i = 0; i < nPnts - 1; ++i)
511 {
512 Int_t a = p.fPnts[i];
513 Int_t b = p.fPnts[i+1];
514 surf += fPnts[a].fX * fPnts[b].fY - fPnts[a].fY * fPnts[b].fX;
515 }
516 return 0.5f * TMath::Abs(surf);
517}
518
519////////////////////////////////////////////////////////////////////////////////
520/// Dump information about built polygons.
521
523{
524 printf("REvePolygonSetProjected %d polygons\n", (Int_t)fPols.size());
525 Int_t cnt = 0;
526 for ( auto &pol : fPols)
527 {
528 Int_t nPnts = pol.NPoints();
529 printf("Points of polygon %d [Np = %d]:\n", ++cnt, nPnts);
530 for (Int_t vi = 0; vi<nPnts; ++vi) {
531 Int_t pi = pol.fPnts[vi];
532 printf(" (%f, %f, %f)", fPnts[pi].fX, fPnts[pi].fY, fPnts[pi].fZ);
533 }
534 printf(", surf=%f\n", PolygonSurfaceXY(pol));
535 }
536}
537
538////////////////////////////////////////////////////////////////////////////////
539/// Dump information about currently projected buffer.
540
542{
543 Int_t* bpols = fBuff->fPols;
544
545 for (UInt_t pi = 0; pi< fBuff->NbPols(); ++pi)
546 {
547 UInt_t segN = bpols[1];
548 printf("%d polygon of %d has %d segments \n", pi, fBuff->NbPols(), segN);
549
550 Int_t* seg = &bpols[2];
551 for (UInt_t a=0; a<segN; ++a)
552 {
553 Int_t a1 = fBuff->fSegs[3*seg[a] + 1];
554 Int_t a2 = fBuff->fSegs[3*seg[a] + 2];
555 printf("(%d, %d) \n", a1, a2);
556 printf("ORIG points :(%f, %f, %f) (%f, %f, %f)\n",
557 fBuff->fPnts[3*a1],fBuff->fPnts[3*a1+1], fBuff->fPnts[3*a1+2],
558 fBuff->fPnts[3*a2],fBuff->fPnts[3*a2+1], fBuff->fPnts[3*a2+2]);
559 }
560 printf("\n");
561 bpols += (segN+2);
562 }
563}
#define d(i)
Definition: RSha256.hxx:102
#define b(i)
Definition: RSha256.hxx:100
#define s0(x)
Definition: RSha256.hxx:90
#define s1(x)
Definition: RSha256.hxx:91
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
float Float_t
Definition: RtypesCore.h:53
const Bool_t kTRUE
Definition: RtypesCore.h:87
segment * segs
Definition: X3DBuffer.c:23
polygon * polys
Definition: X3DBuffer.c:24
void ProcessData(const std::vector< Double_t > &verts, const std::vector< Int_t > &polys, const Int_t n_polys)
ProcessData.
virtual Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset)
Write core json.
std::unique_ptr< REveRenderData > fRenderData
Externally assigned and controlled user data.
virtual std::unique_ptr< TBuffer3D > MakeBuffer3D()
Create a TBuffer3D suitable for presentation of the shape.
void SetProjection(REveProjectionManager *mng, REveProjectable *model) override
This is virtual method from base-class REveProjected.
virtual void DumpPolys() const
Dump information about built polygons.
Bool_t IsFirstIdxHead(Int_t s0, Int_t s1)
Compare the two segments and check if the first index of first segment is starting.
Float_t AddPolygon(std::list< Int_t > &pp, std::list< Polygon_t > &p)
Check if polygon has dimensions above REveProjection::fgEps and add it to a list if it is not a dupli...
vpPolygon_t fPolsBS
! polygons build from TBuffer3D segments
void BuildRenderData() override
Crates representation for rendering.
void DumpBuffer3D()
Dump information about currently projected buffer.
void UpdateProjection() override
This is virtual method from base-class REveProjected.
vpPolygon_t fPolsBP
! polygons build from TBuffer3D polygons
Float_t MakePolygonsFromBS(std::vector< Int_t > &idxMap)
Build polygons from the set of buffer segments.
std::vector< REveVector > fPnts
! reduced and projected points
std::vector< Int_t > ProjectAndReducePoints()
Project and reduce buffer points.
Float_t PolygonSurfaceXY(const Polygon_t &poly) const
Calculate XY surface of a polygon.
void ComputeBBox() override
Override of virtual method from TAttBBox.
Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override
Fill core part of JSON representation.
void SetDepthLocal(Float_t d) override
Set depth (z-coordinate) of the projected points.
Float_t MakePolygonsFromBP(std::vector< Int_t > &idxMap)
Build polygons from list of buffer polygons.
virtual void SetProjection(REveProjectionManager *mng, REveProjectable *model)
Sets projection manager and reference in the projectable object.
void SetDepthCommon(Float_t d, REveElement *el, Float_t *bbox)
Utility function to update the z-values of the bounding-box.
REveProjectionManager Manager class for steering of projections and managing projected objects.
REveProjection Base for specific classes that implement non-linear projections.
virtual void ProjectPoint(Float_t &x, Float_t &y, Float_t &z, Float_t d, EPProc_e p=kPP_Full)=0
virtual Bool_t AcceptSegment(REveVector &, REveVector &, Float_t) const
void CopyVizParams(const REveElement *el) override
Copy visualization parameters from element el.
Definition: REveShape.cxx:89
void BBoxCheckPoint(Float_t x, Float_t y, Float_t z)
Definition: TAttBBox.h:58
void ResetBBox()
Definition: TAttBBox.h:46
void BBoxZero(Float_t epsilon=0, Float_t x=0, Float_t y=0, Float_t z=0)
Create cube of volume (2*epsilon)^3 at (x,y,z).
Definition: TAttBBox.cxx:42
void BBoxInit(Float_t infinity=1e6)
Dynamic Float_t[6] X(min,max), Y(min,max), Z(min,max)
Definition: TAttBBox.cxx:29
Float_t * fBBox
Definition: TAttBBox.h:20
const Int_t n
Definition: legend1.C:16
static constexpr double s
static constexpr double pi
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
const char * cnt
Definition: TXMLSetup.cxx:74
auto * a
Definition: textangle.C:12