Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 <cassert>
22
23#include <nlohmann/json.hpp>
24
25using namespace 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
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 // check the shape is not just a holder
91 if (fPnts.empty())
92 return;
93
94 fRenderData = std::make_unique<REveRenderData>("makePolygonSetProjected", 3 * fPnts.size());
95
96 Int_t n_pols = fPols.size();
97 Int_t n_poly_info = 0;
98 for (auto &p : fPols) n_poly_info += 1 + p.NPoints();
99
100 std::vector<Double_t> verts;
101 verts.reserve(3 * fPnts.size());
102 std::vector<UInt_t> polys;
103 polys.reserve(n_poly_info);
104
105 for (auto &p : fPols)
106 {
107 polys.emplace_back(p.NPoints());
108 polys.insert(polys.end(), p.fPnts.begin(), p.fPnts.end());
109 }
110
111 for (unsigned i = 0; i < fPnts.size(); ++i)
112 {
113 verts.push_back(fPnts[i].fX);
114 verts.push_back(fPnts[i].fY);
115 verts.push_back(fPnts[i].fZ);
116 fRenderData->PushV(fPnts[i]);
117 }
118
119 Int_t n_trings = 0;
120 {
122
123 tc.ProcessData(verts, polys, n_pols);
124
125 polys.swap(tc.RefPolyDesc());
126 n_trings = tc.GetNTrianlges();
127 }
128
129 // Calculate size of index buffer.
130 Int_t n_idxbuff = 2 + 3 * n_trings + n_pols + n_poly_info;
131 fRenderData->Reserve(0,0,n_idxbuff);
132
133 assert(n_trings * 4 == (int)polys.size());
134
135 // Export triangles.
137 fRenderData->PushI(n_trings);
138 for (int i = 0; i < n_trings; ++i)
139 {
140 fRenderData->PushI(&polys[i*4 + 1], 3);
141 }
142
143 assert (fRenderData->SizeI() == 2 + 3 * n_trings);
144
145 // Export outlines.
146 for (auto &p : fPols)
147 {
149 fRenderData->PushI(p.NPoints());
150 fRenderData->PushI(p.fPnts);
151 }
152
153 assert (fRenderData->SizeI() == n_idxbuff);
154}
155
156////////////////////////////////////////////////////////////////////////////////
157/// Override of virtual method from TAttBBox.
158
160{
161 if (!fPnts.empty()) {
162 BBoxInit();
163 for (unsigned pi = 0; pi < fPnts.size(); ++pi)
164 BBoxCheckPoint(fPnts[pi].fX, fPnts[pi].fY, fPnts[pi].fZ);
165 } else {
166 BBoxZero();
167 }
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// This is virtual method from base-class REveProjected.
172
174 REveProjectable* model)
175{
177
178 REveGeoShape* gre = dynamic_cast<REveGeoShape*>(model);
179 fBuff = gre->MakeBuffer3D();
180 CopyVizParams(gre);
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Set depth (z-coordinate) of the projected points.
185
187{
188 SetDepthCommon(d, this, fBBox);
189
190 for (unsigned i = 0; i < fPnts.size(); ++i)
191 fPnts[i].fZ = fDepth;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// This is virtual method from base-class REveProjected.
196
198{
199 if (!fBuff) return;
200
201 // drop polygons and projected/reduced points
202 fPols.clear();
204}
205
206////////////////////////////////////////////////////////////////////////////////
207/// Compare the two segments and check if the first index of first segment is starting.
208
210{
211 Int_t v0 = fBuff->fSegs[3*s0 + 1];
212 Int_t v2 = fBuff->fSegs[3*s1 + 1];
213 Int_t v3 = fBuff->fSegs[3*s1 + 2];
214 return v0 != v2 && v0 != v3;
215}
216
217////////////////////////////////////////////////////////////////////////////////
218/// Project and reduce buffer points.
219
221{
222 REveProjection* projection = fManager->GetProjection();
223
224 Int_t buffN = fBuff->NbPnts();
225 std::vector<REveVector> pnts; pnts.resize(buffN);
226 for (Int_t i = 0; i < buffN; ++i)
227 {
228 pnts[i].Set(fBuff->fPnts[3*i],fBuff->fPnts[3*i+1], fBuff->fPnts[3*i+2]);
229 projection->ProjectPoint(pnts[i].fX, pnts[i].fY, pnts[i].fZ, 0,
231 }
232
233 int npoints = 0;
234 std::vector<UInt_t> idxMap;
235 idxMap.resize(buffN);
236
237 std::vector<int> ra;
238 ra.resize(buffN); // list of reduced vertices
239 for (UInt_t v = 0; v < (UInt_t)buffN; ++v)
240 {
241 bool found = false;
242 for (Int_t k = 0; k < npoints; ++k)
243 {
244 if (pnts[v].SquareDistance(pnts[ra[k]]) < REveProjection::fgEpsSqr)
245 {
246 idxMap[v] = k;
247 found = true;
248 break;
249 }
250 }
251 // have not found a point inside epsilon, add new point in scaled array
252 if (!found)
253 {
254 idxMap[v] = npoints;
255 ra[npoints] = v;
256 ++npoints;
257 }
258 }
259
260 // write the array of scaled points
261 fPnts.resize(npoints);
262 for (Int_t idx = 0; idx < npoints; ++idx)
263 {
264 Int_t i = ra[idx];
265 projection->ProjectPoint(pnts[i].fX, pnts[i].fY, pnts[i].fZ, fDepth,
267 fPnts[idx].Set(pnts[i]);
268 }
269 // printf("reduced %d points of %d\n", fNPnts, N);
270
271 return idxMap;
272}
273
274////////////////////////////////////////////////////////////////////////////////
275/// Check if polygon has dimensions above REveProjection::fgEps and add it
276/// to a list if it is not a duplicate.
277
279{
280 if (pp.size() <= 2) return 0;
281
282 Float_t bbox[4] = { 1e6, -1e6, 1e6, -1e6 };
283 for (auto &&idx: pp)
284 {
285 if (fPnts[idx].fX < bbox[0]) bbox[0] = fPnts[idx].fX;
286 if (fPnts[idx].fX > bbox[1]) bbox[1] = fPnts[idx].fX;
287
288 if (fPnts[idx].fY < bbox[2]) bbox[2] = fPnts[idx].fY;
289 if (fPnts[idx].fY > bbox[3]) bbox[3] = fPnts[idx].fY;
290 }
292 if ((bbox[1]-bbox[0]) < eps || (bbox[3]-bbox[2]) < eps) return 0;
293
294 // Duplication
295 for (auto &&refP : pols)
296 {
297 if ((Int_t) pp.size() != refP.NPoints())
298 continue;
299
300 int start_idx = refP.FindPoint(pp.front());
301 if (start_idx < 0)
302 continue;
303 if (++start_idx >= refP.NPoints()) start_idx = 0;
304
305 // Same orientation duplicate
306 {
307 auto u = ++pp.begin();
308 Int_t pidx = start_idx;
309 while (u != pp.end())
310 {
311 if ((*u) != refP.fPnts[pidx])
312 break;
313 ++u;
314 if (++pidx >= refP.NPoints()) pidx = 0;
315 }
316 if (u == pp.end()) return 0;
317 }
318 // Inverse orientation duplicate
319 {
320 auto u = --pp.end();
321 Int_t pidx = start_idx;
322 while (u != pp.begin())
323 {
324 if ((*u) != refP.fPnts[pidx])
325 break;
326 --u;
327 if (++pidx >= refP.NPoints()) pidx = 0;
328 }
329 if (u == pp.begin()) return 0;
330 }
331 }
332
333 std::vector<UInt_t> pv(pp.size(), 0);
334 int count = 0;
335 for (auto &&u : pp) {
336 pv[count++] = u;
337 }
338
339 pols.emplace_back(std::move(pv));
340
341 return (bbox[1]-bbox[0]) * (bbox[3]-bbox[2]);
342}
343
344////////////////////////////////////////////////////////////////////////////////
345/// Build polygons from list of buffer polygons.
346
348{
349 REveProjection* projection = fManager->GetProjection();
350 Int_t *bpols = fBuff->fPols;
351 Float_t surf = 0; // surface of projected polygons
352 for (UInt_t pi = 0; pi < fBuff->NbPols(); ++pi)
353 {
354 std::list<UInt_t> pp; // points in current polygon
355 UInt_t segN = bpols[1];
356 Int_t *seg = &bpols[2];
357 // start idx in the fist segment depends of second segment
358 UInt_t tail, head;
359 if (IsFirstIdxHead(seg[0], seg[1]))
360 {
361 head = idxMap[fBuff->fSegs[3*seg[0] + 1]];
362 tail = idxMap[fBuff->fSegs[3*seg[0] + 2]];
363 }
364 else
365 {
366 head = idxMap[fBuff->fSegs[3*seg[0] + 2]];
367 tail = idxMap[fBuff->fSegs[3*seg[0] + 1]];
368 }
369 pp.emplace_back(head);
370 // printf("start idx head %d, tail %d\n", head, tail);
371 LSeg_t segs;
372 for (UInt_t s = 1; s < segN; ++s)
373 segs.emplace_back(fBuff->fSegs[3*seg[s] + 1],fBuff->fSegs[3*seg[s] + 2]);
374
375 for (auto &it: segs)
376 {
377 UInt_t mv1 = idxMap[it.fV1];
378 UInt_t mv2 = idxMap[it.fV2];
379
380 if ( ! projection->AcceptSegment(fPnts[mv1], fPnts[mv2], REveProjection::fgEps))
381 {
382 pp.clear();
383 break;
384 }
385 if (tail != pp.back()) pp.push_back(tail);
386 tail = (mv1 == tail) ? mv2 : mv1;
387 }
388
389 if ( ! pp.empty())
390 {
391 // DirectDraw() implementation: last and first vertices should not be equal
392 if (pp.front() == pp.back()) pp.pop_front();
393 surf += AddPolygon(pp, fPolsBP);
394 }
395 bpols += (segN+2);
396 }
397 return surf;
398}
399
400////////////////////////////////////////////////////////////////////////////////
401/// Build polygons from the set of buffer segments.
402/// First creates a segment pool according to reduced and projected points
403/// and then build polygons from the pool.
404
406{
407 LSeg_t segs;
408 Float_t surf = 0; // surface of projected polygons
409 REveProjection *projection = fManager->GetProjection();
410 for (UInt_t s = 0; s < fBuff->NbSegs(); ++s)
411 {
412 Bool_t duplicate = kFALSE;
413 Int_t vo1, vo2; // idx from fBuff segment
414 Int_t vor1, vor2; // mapped idx
415 vo1 = fBuff->fSegs[3*s + 1];
416 vo2 = fBuff->fSegs[3*s + 2]; //... skip color info
417 vor1 = idxMap[vo1];
418 vor2 = idxMap[vo2];
419 if (vor1 == vor2) continue;
420 // check duplicate
421 for (auto &seg: segs)
422 {
423 Int_t vv1 = seg.fV1;
424 Int_t vv2 = seg.fV2;
425 if((vv1 == vor1 && vv2 == vor2) || (vv1 == vor2 && vv2 == vor1))
426 {
427 duplicate = kTRUE;
428 continue;
429 }
430 }
431 if (duplicate == kFALSE && projection->AcceptSegment(fPnts[vor1], fPnts[vor2], REveProjection::fgEps))
432 segs.emplace_back(vor1, vor2);
433 }
434
435 while (!segs.empty())
436 {
437 std::list<UInt_t> pp; // points in current polygon
438 pp.push_back(segs.front().fV1);
439 UInt_t tail = segs.front().fV2;
440 segs.pop_front();
441 Bool_t match = kTRUE;
442 while (match && ! segs.empty())
443 {
444 for (auto k = segs.begin(); k != segs.end(); ++k)
445 {
446 UInt_t cv1 = (*k).fV1;
447 UInt_t cv2 = (*k).fV2;
448 if (cv1 == tail || cv2 == tail)
449 {
450 pp.emplace_back(tail);
451 tail = (cv1 == tail) ? cv2 : cv1;
452 segs.erase(k);
453 match = kTRUE;
454 break;
455 }
456 else
457 {
458 match = kFALSE;
459 }
460 } // end for loop in the segment pool
461 if (tail == pp.front())
462 break;
463 }
464 surf += AddPolygon(pp, fPolsBS);
465 }
466 return surf;
467}
468
469////////////////////////////////////////////////////////////////////////////////
470/// Project current buffer.
471
473{
474 // create map from original to projected and reduced point needed only for geometry
475 auto idxMap = ProjectAndReducePoints();
476
478 switch (mode) {
480 MakePolygonsFromBP(idxMap);
481 fPolsBP.swap(fPols);
482 break;
483 }
485 MakePolygonsFromBS(idxMap);
486 fPolsBS.swap(fPols);
487 break;
488 }
490 // take projection with largest surface
491 Float_t surfBP = MakePolygonsFromBP(idxMap);
492 Float_t surfBS = MakePolygonsFromBS(idxMap);
493 if (surfBS < surfBP) {
494 fPolsBP.swap(fPols);
495 fPolsBS.clear();
496 } else {
497 fPolsBS.swap(fPols);
498 fPolsBP.clear();
499 }
500 break;
501 }
502 default: break;
503 }
504
505 ResetBBox();
506}
507
508////////////////////////////////////////////////////////////////////////////////
509/// Calculate XY surface of a polygon.
510
512{
513 Float_t surf = 0;
514 Int_t nPnts = p.NPoints();
515 for (Int_t i = 0; i < nPnts - 1; ++i)
516 {
517 Int_t a = p.fPnts[i];
518 Int_t b = p.fPnts[i+1];
519 surf += fPnts[a].fX * fPnts[b].fY - fPnts[a].fY * fPnts[b].fX;
520 }
521 return 0.5f * TMath::Abs(surf);
522}
523
524////////////////////////////////////////////////////////////////////////////////
525/// Dump information about built polygons.
526
528{
529 printf("REvePolygonSetProjected %d polygons\n", (Int_t)fPols.size());
530 Int_t cnt = 0;
531 for ( auto &pol : fPols)
532 {
533 Int_t nPnts = pol.NPoints();
534 printf("Points of polygon %d [Np = %d]:\n", ++cnt, nPnts);
535 for (Int_t vi = 0; vi<nPnts; ++vi) {
536 Int_t pi = pol.fPnts[vi];
537 printf(" (%f, %f, %f)", fPnts[pi].fX, fPnts[pi].fY, fPnts[pi].fZ);
538 }
539 printf(", surf=%f\n", PolygonSurfaceXY(pol));
540 }
541}
542
543////////////////////////////////////////////////////////////////////////////////
544/// Dump information about currently projected buffer.
545
547{
548 Int_t* bpols = fBuff->fPols;
549
550 for (UInt_t pi = 0; pi< fBuff->NbPols(); ++pi)
551 {
552 UInt_t segN = bpols[1];
553 printf("%d polygon of %d has %d segments \n", pi, fBuff->NbPols(), segN);
554
555 Int_t* seg = &bpols[2];
556 for (UInt_t a=0; a<segN; ++a)
557 {
558 Int_t a1 = fBuff->fSegs[3*seg[a] + 1];
559 Int_t a2 = fBuff->fSegs[3*seg[a] + 2];
560 printf("(%d, %d) \n", a1, a2);
561 printf("ORIG points :(%f, %f, %f) (%f, %f, %f)\n",
562 fBuff->fPnts[3*a1],fBuff->fPnts[3*a1+1], fBuff->fPnts[3*a1+2],
563 fBuff->fPnts[3*a2],fBuff->fPnts[3*a2+1], fBuff->fPnts[3*a2+2]);
564 }
565 printf("\n");
566 bpols += (segN+2);
567 }
568}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define s0(x)
Definition RSha256.hxx:90
#define a(i)
Definition RSha256.hxx:99
#define s1(x)
Definition RSha256.hxx:91
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char mode
void ProcessData(const std::vector< Double_t > &verts, const std::vector< UInt_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
! Vertex / normal / triangle index information for rendering.
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.
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
std::vector< UInt_t > ProjectAndReducePoints()
Project and reduce buffer points.
std::vector< REveVector > fPnts
! reduced and projected points
Float_t PolygonSurfaceXY(const Polygon_t &poly) const
Calculate XY surface of a polygon.
void ComputeBBox() override
Override of virtual method from TAttBBox.
Float_t MakePolygonsFromBS(std::vector< UInt_t > &idxMap)
Build polygons from the set of buffer segments.
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< UInt_t > &idxMap)
Build polygons from list of buffer polygons.
Float_t AddPolygon(std::list< UInt_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...
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:82
void BBoxCheckPoint(Float_t x, Float_t y, Float_t z)
Definition TAttBBox.h:69
void ResetBBox()
Definition TAttBBox.h:57
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:41
void BBoxInit(Float_t infinity=1e6)
Allocate and prepare for incremental filling.
Definition TAttBBox.cxx:28
Float_t * fBBox
! Dynamic Float_t[6] X(min,max), Y(min,max), Z(min,max)
Definition TAttBBox.h:20
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122