Logo ROOT  
Reference Guide
REveGeoPolyShape.cxx
Go to the documentation of this file.
1// @(#)root/eve7:$Id$
2// Author: Matevz Tadel 2007, 2018
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
12#include "Rtypes.h"
13#include <cassert>
14
15
17#include <ROOT/REveGeoShape.hxx>
18#include <ROOT/REveUtil.hxx>
19#include <ROOT/REveGluTess.hxx>
21
22#include "TBuffer3D.h"
23#include "TBuffer3DTypes.h"
24#include "CsgOps.h"
25
26#include "TGeoBoolNode.h"
27#include "TGeoCompositeShape.h"
28#include "TGeoMatrix.h"
29
30using namespace ROOT::Experimental;
31
32/** \class REveGeoPolyShape
33\ingroup REve
34Description of REveGeoPolyShape
35*/
36
37Bool_t REveGeoPolyShape::fgAutoEnforceTriangles = kTRUE;
38Bool_t REveGeoPolyShape::fgAutoCalculateNormals = kFALSE;
39
40void REveGeoPolyShape::SetAutoEnforceTriangles(Bool_t f) { fgAutoEnforceTriangles = f; }
44
45////////////////////////////////////////////////////////////////////////
46/// Function produces mesh for provided shape, applying matrix to the result
47
48std::unique_ptr<RootCsg::TBaseMesh> MakeGeoMesh(TGeoMatrix *matr, TGeoShape *shape)
49{
50 TGeoCompositeShape *comp = dynamic_cast<TGeoCompositeShape *> (shape);
51
52 std::unique_ptr<RootCsg::TBaseMesh> res;
53
54 if (!comp) {
55 std::unique_ptr<TBuffer3D> b3d(shape->MakeBuffer3D());
56
57 if (matr) {
58 Double_t *v = b3d->fPnts;
59 Double_t buf[3];
60 for (UInt_t i = 0; i < b3d->NbPnts(); ++i) {
61 buf[0] = v[i*3];
62 buf[1] = v[i*3+1];
63 buf[2] = v[i*3+2];
64 matr->LocalToMaster(buf, &v[i*3]);
65 }
66 }
67
68 res.reset(RootCsg::ConvertToMesh(*b3d.get()));
69 } else {
70 auto node = comp->GetBoolNode();
71
72 TGeoHMatrix mleft, mright;
73 if (matr) { mleft = *matr; mright = *matr; }
74
75 mleft.Multiply(node->GetLeftMatrix());
76 auto left = MakeGeoMesh(&mleft, node->GetLeftShape());
77
78 mright.Multiply(node->GetRightMatrix());
79 auto right = MakeGeoMesh(&mright, node->GetRightShape());
80
81 if (node->IsA() == TGeoUnion::Class()) res.reset(RootCsg::BuildUnion(left.get(), right.get()));
82 if (node->IsA() == TGeoIntersection::Class()) res.reset(RootCsg::BuildIntersection(left.get(), right.get()));
83 if (node->IsA() == TGeoSubtraction::Class()) res.reset(RootCsg::BuildDifference(left.get(), right.get()));
84 }
85
86 return res;
87}
88
89////////////////////////////////////////////////////////////////////////////////
90/// Produce all polygons from composite shape
91
93{
94 fOrigin[0] = cshape->GetOrigin()[0];
95 fOrigin[1] = cshape->GetOrigin()[1];
96 fOrigin[2] = cshape->GetOrigin()[2];
97 fDX = cshape->GetDX();
98 fDY = cshape->GetDY();
99 fDZ = cshape->GetDZ();
100
102
103 auto mesh = MakeGeoMesh(nullptr, cshape);
104
105 Int_t nv = mesh->NumberOfVertices();
106 fVertices.reserve(3 * nv);
107
108 for (Int_t i = 0; i < nv; ++i) {
109 auto v = mesh->GetVertex(i);
110 fVertices.insert(fVertices.end(), v, v + 3);
111 }
112
113 fNbPols = mesh->NumberOfPolys();
114
115 Int_t descSize = 0;
116
117 for (Int_t i = 0; i < fNbPols; ++i) descSize += mesh->SizeOfPoly(i) + 1;
118
119 fPolyDesc.reserve(descSize);
120
121 for (Int_t polyIndex = 0; polyIndex < fNbPols; ++polyIndex) {
122 Int_t polySize = mesh->SizeOfPoly(polyIndex);
123
124 fPolyDesc.push_back(polySize);
125
126 for (Int_t i = 0; i < polySize; ++i)
127 fPolyDesc.push_back(mesh->GetVertexIndex(polyIndex, i));
128 }
129
132}
133
134////////////////////////////////////////////////////////////////////////////////
135/// Produce all polygons from normal shape
136
138{
139 TGeoBBox *box = dynamic_cast<TGeoBBox *> (shape);
140
141 if (box) {
142 fOrigin[0] = box->GetOrigin()[0];
143 fOrigin[1] = box->GetOrigin()[1];
144 fOrigin[2] = box->GetOrigin()[2];
145 fDX = box->GetDX();
146 fDY = box->GetDY();
147 fDZ = box->GetDZ();
148 }
149
151
152 std::unique_ptr<TBuffer3D> b3d(shape->MakeBuffer3D());
153
154 SetFromBuff3D(*b3d.get());
155}
156
157////////////////////////////////////////////////////////////////////////////////
158
160{
161 // We know all elements are triangles. Or at least they should be.
162
163 rd.Reserve(fVertices.size(), fNormals.size(), 2 + fNbPols * 3);
164
165 for (auto &v: fVertices)
166 rd.PushV(v);
167
168 for (auto &n: fNormals)
169 rd.PushN(n);
170
172 rd.PushI(fNbPols);
173
174 // count number of index entries etc
175 for (Int_t i = 0, j = 0; i < fNbPols; ++i) {
176 assert(fPolyDesc[j] == 3);
177
178 rd.PushI(fPolyDesc[j + 1], fPolyDesc[j + 2], fPolyDesc[j + 3]);
179 j += 1 + fPolyDesc[j];
180 }
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Set data-members from a Csg mesh.
185
186
188{
189 fNbPols = (Int_t) buffer.NbPols();
190
191 if (fNbPols == 0) return;
192
193 fVertices.insert(fVertices.end(), buffer.fPnts, buffer.fPnts + 3 * buffer.NbPnts());
194
195 Int_t *segs = buffer.fSegs;
196 Int_t *pols = buffer.fPols;
197
198 Int_t descSize = 0;
199
200 for (Int_t i = 0, j = 1; i < fNbPols; ++i, ++j)
201 {
202 descSize += pols[j] + 1;
203 j += pols[j] + 1;
204 }
205
206 fPolyDesc.resize(descSize);
207
208 for (Int_t numPol = 0, currInd = 0, j = 1; numPol < fNbPols; ++numPol)
209 {
210 Int_t segmentInd = pols[j] + j;
211 Int_t segmentCol = pols[j];
212 Int_t s1 = pols[segmentInd];
213 segmentInd--;
214 Int_t s2 = pols[segmentInd];
215 segmentInd--;
216 Int_t segEnds[] = {segs[s1 * 3 + 1], segs[s1 * 3 + 2],
217 segs[s2 * 3 + 1], segs[s2 * 3 + 2]};
218 Int_t numPnts[3];
219
220 if (segEnds[0] == segEnds[2]) {
221 numPnts[0] = segEnds[1]; numPnts[1] = segEnds[0]; numPnts[2] = segEnds[3];
222 } else if (segEnds[0] == segEnds[3]) {
223 numPnts[0] = segEnds[1]; numPnts[1] = segEnds[0]; numPnts[2] = segEnds[2];
224 } else if (segEnds[1] == segEnds[2]) {
225 numPnts[0] = segEnds[0]; numPnts[1] = segEnds[1]; numPnts[2] = segEnds[3];
226 } else {
227 numPnts[0] = segEnds[0]; numPnts[1] = segEnds[1]; numPnts[2] = segEnds[2];
228 }
229
230 fPolyDesc[currInd] = 3;
231 Int_t sizeInd = currInd++;
232 fPolyDesc[currInd++] = numPnts[0];
233 fPolyDesc[currInd++] = numPnts[1];
234 fPolyDesc[currInd++] = numPnts[2];
235 Int_t lastAdded = numPnts[2];
236
237 Int_t end = j + 1;
238 for (; segmentInd != end; segmentInd--) {
239 segEnds[0] = segs[pols[segmentInd] * 3 + 1];
240 segEnds[1] = segs[pols[segmentInd] * 3 + 2];
241 if (segEnds[0] == lastAdded) {
242 fPolyDesc[currInd++] = segEnds[1];
243 lastAdded = segEnds[1];
244 } else {
245 fPolyDesc[currInd++] = segEnds[0];
246 lastAdded = segEnds[0];
247 }
248 ++fPolyDesc[sizeInd];
249 }
250 j += segmentCol + 2;
251 }
252
255}
256
257////////////////////////////////////////////////////////////////////////////////
258/// Use GLU tesselator to replace all polygons with N > 3 with triangles.
259/// After this call polygon descriptions are changed.
260/// New vertices are not expected -- exception is thrown if this is
261/// requested by the triangulator. Support for adding of new vertices can be
262/// provided.
263
265{
267
269
270 fPolyDesc.swap(tc.RefPolyDesc());
271 fNbPols = tc.GetNTrianlges();
272}
273
274////////////////////////////////////////////////////////////////////////////////
275/// CalculateNormals per polygon (flat shading)
276
278{
279 fNormals.resize(3 * fNbPols);
280 if (fNbPols == 0) return;
281 Double_t *pnts = &fVertices[0];
282 for (Int_t i = 0, j = 0; i < fNbPols; ++i)
283 {
284 Int_t polEnd = fPolyDesc[j] + j + 1;
285 UInt_t norm[] = {fPolyDesc[j + 1], fPolyDesc[j + 2], fPolyDesc[j + 3]};
286 j += 4;
287 Int_t check = CheckPoints(norm, norm);
288 Int_t ngood = check;
289 if (check == 3) {
290 TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
291 pnts + norm[2] * 3, &fNormals[i * 3]);
292 j = polEnd;
293 continue;
294 }
295 while (j < polEnd)
296 {
297 norm[ngood++] = fPolyDesc[j++];
298 if (ngood == 3) {
299 ngood = CheckPoints(norm, norm);
300 if (ngood == 3) {
301 TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
302 pnts + norm[2] * 3, &fNormals[i * 3]);
303 j = polEnd;
304 break;
305 }
306 }
307 }
308 }
309}
310
311////////////////////////////////////////////////////////////////////////////////
312/// CheckPoints
313
315{
316 const Double_t * p1 = &fVertices[source[0] * 3];
317 const Double_t * p2 = &fVertices[source[1] * 3];
318 const Double_t * p3 = &fVertices[source[2] * 3];
319 Int_t retVal = 1;
320
321 if (Eq(p1, p2)) {
322 dest[0] = source[0];
323 if (!Eq(p1, p3) ) {
324 dest[1] = source[2];
325 retVal = 2;
326 }
327 } else if (Eq(p1, p3)) {
328 dest[0] = source[0];
329 dest[1] = source[1];
330 retVal = 2;
331 } else {
332 dest[0] = source[0];
333 dest[1] = source[1];
334 retVal = 2;
335 if (!Eq(p2, p3)) {
336 dest[2] = source[2];
337 retVal = 3;
338 }
339 }
340
341 return retVal;
342}
343
344////////////////////////////////////////////////////////////////////////////////
345/// Test equality of points with epsilon 1e-10.
346
348{
349 Double_t dx = TMath::Abs(p1[0] - p2[0]);
350 Double_t dy = TMath::Abs(p1[1] - p2[1]);
351 Double_t dz = TMath::Abs(p1[2] - p2[2]);
352 return (dx < 1e-10) && (dy < 1e-10) && (dz < 1e-10);
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Fill the passed buffer 3D.
357
359{
360 if (reqSections & TBuffer3D::kCore)
361 {
362 // If writing core section all others will be invalid
363 b.ClearSectionsValid();
364
365 b.fID = const_cast<REveGeoPolyShape*>(this);
366 b.fColor = kMagenta;
367 b.fTransparency = 0;
368 b.fLocalFrame = kFALSE;
369 b.fReflection = kTRUE;
370
371 b.SetSectionsValid(TBuffer3D::kCore);
372 }
373
374 if ((reqSections & TBuffer3D::kRawSizes) || (reqSections & TBuffer3D::kRaw))
375 {
376 Int_t nvrt = fVertices.size() / 3;
377 Int_t nseg = 0;
378
379 std::map<Edge_t, Int_t> edges;
380
381 const UInt_t *pd = &fPolyDesc[0];
382 for (Int_t i = 0; i < fNbPols; ++i) {
383 Int_t nv = pd[0];
384 ++pd;
385 for (Int_t j = 0; j < nv; ++j) {
386 Edge_t e(pd[j], (j != nv - 1) ? pd[j + 1] : pd[0]);
387 if (edges.find(e) == edges.end()) {
388 edges.insert(std::make_pair(e, 0));
389 ++nseg;
390 }
391 }
392 pd += nv;
393 }
394
395 b.SetRawSizes(nvrt, 3*nvrt, nseg, 3*nseg, fNbPols, fNbPols+fPolyDesc.size());
396
397 memcpy(b.fPnts, &fVertices[0], sizeof(Double_t)*fVertices.size());
398
399 Int_t si = 0, scnt = 0;
400 for (auto &edge : edges) {
401 b.fSegs[si++] = 0;
402 b.fSegs[si++] = edge.first.fI;
403 b.fSegs[si++] = edge.first.fJ;
404 edge.second = scnt++;
405 }
406
407 Int_t pi = 0;
408 pd = &fPolyDesc[0];
409 for (Int_t i = 0; i < fNbPols; ++i) {
410 Int_t nv = pd[0];
411 ++pd;
412 b.fPols[pi++] = 0;
413 b.fPols[pi++] = nv;
414 for (Int_t j = 0; j < nv; ++j) {
415 b.fPols[pi++] = edges[Edge_t(pd[j], (j != nv - 1) ? pd[j + 1] : pd[0])];
416 }
417 pd += nv;
418 }
419
420 b.SetSectionsValid(TBuffer3D::kRawSizes | TBuffer3D::kRaw);
421 }
422}
423
424////////////////////////////////////////////////////////////////////////////////
425/// Fill static buffer 3D.
426
427const TBuffer3D& REveGeoPolyShape::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
428{
430
431 FillBuffer3D(buf, reqSections, localFrame);
432
433 return buf;
434}
435
436////////////////////////////////////////////////////////////////////////////////
437/// Create buffer 3D and fill it with point/segment/poly data.
438
440{
441 auto *buf = new TBuffer3D(TBuffer3DTypes::kGeneric);
442
444
445 return buf;
446}
std::unique_ptr< RootCsg::TBaseMesh > MakeGeoMesh(TGeoMatrix *matr, TGeoShape *shape)
Function produces mesh for provided shape, applying matrix to the result.
#define f(i)
Definition: RSha256.hxx:104
#define s1(x)
Definition: RSha256.hxx:91
#define e(i)
Definition: RSha256.hxx:103
int Int_t
Definition: RtypesCore.h:45
const Bool_t kFALSE
Definition: RtypesCore.h:101
const Bool_t kTRUE
Definition: RtypesCore.h:100
@ kMagenta
Definition: Rtypes.h:66
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t b
segment * segs
Definition: X3DBuffer.c:23
void ProcessData(const std::vector< Double_t > &verts, const std::vector< UInt_t > &polys, const Int_t n_polys)
ProcessData.
REveGeoManagerHolder Exception-safe global variable holders.
Definition: REveUtil.hxx:87
void FillRenderData(REveRenderData &rd)
virtual void FillBuffer3D(TBuffer3D &buffer, Int_t reqSections, Bool_t localFrame) const
Fill the passed buffer 3D.
static void SetAutoCalculateNormals(Bool_t f)
void EnforceTriangles()
Use GLU tesselator to replace all polygons with N > 3 with triangles.
void BuildFromShape(TGeoShape *shape, Int_t n_seg=60)
Produce all polygons from normal shape.
void BuildFromComposite(TGeoCompositeShape *cshp, Int_t n_seg=60)
Produce all polygons from composite shape.
virtual TBuffer3D * MakeBuffer3D() const
Create buffer 3D and fill it with point/segment/poly data.
virtual const TBuffer3D & GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
Fill static buffer 3D.
void CalculateNormals()
CalculateNormals per polygon (flat shading)
Int_t CheckPoints(const UInt_t *source, UInt_t *dest) const
CheckPoints.
void SetFromBuff3D(const TBuffer3D &buffer)
Set data-members from a Csg mesh.
static Bool_t Eq(const Double_t *p1, const Double_t *p2)
Test equality of points with epsilon 1e-10.
static TGeoManager * GetGeoManager()
Return static geo-manager that is used internally to make shapes lead a happy life.
void Reserve(int size_vert=0, int size_norm=0, int size_idx=0)
Reserve place for render data.
Generic 3D primitive description class.
Definition: TBuffer3D.h:18
Int_t * fPols
Definition: TBuffer3D.h:114
UInt_t NbPols() const
Definition: TBuffer3D.h:82
UInt_t NbPnts() const
Definition: TBuffer3D.h:80
@ kRawSizes
Definition: TBuffer3D.h:53
Int_t * fSegs
Definition: TBuffer3D.h:113
Double_t * fPnts
Definition: TBuffer3D.h:112
Box class.
Definition: TGeoBBox.h:18
virtual const Double_t * GetOrigin() const
Definition: TGeoBBox.h:77
Double_t fDX
Definition: TGeoBBox.h:21
virtual Double_t GetDX() const
Definition: TGeoBBox.h:74
virtual Double_t GetDZ() const
Definition: TGeoBBox.h:76
virtual Double_t GetDY() const
Definition: TGeoBBox.h:75
Double_t fOrigin[3]
Definition: TGeoBBox.h:24
Double_t fDY
Definition: TGeoBBox.h:22
Double_t fDZ
Definition: TGeoBBox.h:23
Composite shapes are Boolean combinations of two or more shape components.
TGeoBoolNode * GetBoolNode() const
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition: TGeoMatrix.h:421
void Multiply(const TGeoMatrix *right)
multiply to the right with an other transformation if right is identity matrix, just return
static TClass * Class()
Geometrical transformation package.
Definition: TGeoMatrix.h:41
virtual void LocalToMaster(const Double_t *local, Double_t *master) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix inverse
Definition: TGeoMatrix.cxx:339
Base abstract class for all shapes.
Definition: TGeoShape.h:26
virtual TBuffer3D * MakeBuffer3D() const
Definition: TGeoShape.h:143
static TClass * Class()
static TClass * Class()
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition: fillpatterns.C:1
const Int_t n
Definition: legend1.C:16
static constexpr double pi
T * Normal2Plane(const T v1[3], const T v2[3], const T v3[3], T normal[3])
Calculates a normal vector of a plane.
Definition: TMath.h:1210
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition: TMathBase.h:123
Definition: triangle.c:632