Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeometryView3D.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GeometryView3D.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
12 #include "Acts/Detector/Portal.hpp"
16 #include "Acts/Geometry/Extent.hpp"
18 #include "Acts/Geometry/Layer.hpp"
31 #include "Acts/Utilities/IAxis.hpp"
34 
35 #include <algorithm>
36 #include <cmath>
37 #include <memory>
38 #include <ostream>
39 #include <utility>
40 #include <vector>
41 
42 #include <limits.h>
43 #include <unistd.h>
44 
45 namespace {
46 
48  if (b.substr(0, 1) == "/" || a.empty()) {
49  return b;
50  }
51 
52  if (a.substr(a.size() - 1) == "/") {
53  return a.substr(a.size() - 1) + "/" + b;
54  }
55 
56  return a + "/" + b;
57 }
58 
59 std::string getWorkingDirectory() {
60  char buffer[PATH_MAX];
61  return (getcwd(buffer, sizeof(buffer)) != nullptr ? std::string(buffer)
62  : std::string(""));
63 }
64 
65 } // namespace
66 
68  const Polyhedron& polyhedron,
69  const ViewConfig& viewConfig) {
70  if (viewConfig.visible) {
71  if (not viewConfig.triangulate) {
72  helper.faces(polyhedron.vertices, polyhedron.faces, viewConfig.color);
73  } else {
74  helper.faces(polyhedron.vertices, polyhedron.triangularMesh,
75  viewConfig.color);
76  }
77  }
78 }
79 
81  const Surface& surface,
82  const GeometryContext& gctx,
83  const Transform3& transform,
84  const ViewConfig& viewConfig) {
85  Polyhedron surfaceHedron =
86  surface.polyhedronRepresentation(gctx, viewConfig.nSegments);
87  if (not transform.isApprox(Transform3::Identity())) {
88  surfaceHedron.move(transform);
89  }
90  drawPolyhedron(helper, surfaceHedron, viewConfig);
91 }
92 
94  IVisualization3D& helper, const SurfaceArray& surfaceArray,
96  const ViewConfig& sensitiveConfig, const ViewConfig& passiveConfig,
97  const ViewConfig& gridConfig, const std::string& _outputDir) {
99  _outputDir == "." ? getWorkingDirectory() : _outputDir;
100  // Draw all the surfaces
101  Extent arrayExtent;
102  for (const auto& sf : surfaceArray.surfaces()) {
103  ViewConfig vConfig = sf->associatedDetectorElement() != nullptr
104  ? sensitiveConfig
105  : passiveConfig;
106  drawSurface(helper, *sf, gctx, transform, vConfig);
107  auto sfExtent = sf->polyhedronRepresentation(gctx, 1).extent();
108  arrayExtent.extend(sfExtent);
109  }
110 
111  if (not sensitiveConfig.outputName.empty()) {
112  helper.write(joinPaths(outputDir, sensitiveConfig.outputName));
113  helper.clear();
114  }
115 
116  double thickness = gridConfig.lineThickness;
117  // Draw the grid itself
118  auto binning = surfaceArray.binningValues();
119  auto axes = surfaceArray.getAxes();
120  if (not binning.empty() and binning.size() == 2 and axes.size() == 2) {
121  // Cylinder surface array
122  if (binning[0] == binPhi and binning[1] == binZ) {
123  double R = arrayExtent.medium(binR) + gridConfig.offset;
124  auto phiValues = axes[0]->getBinEdges();
125  auto zValues = axes[1]->getBinEdges();
126  ViewConfig gridRadConfig = gridConfig;
127  gridRadConfig.nSegments = phiValues.size();
128  // Longitudinal lines
129  for (auto phi : phiValues) {
130  double cphi = std::cos(phi);
131  double sphi = std::sin(phi);
132  Vector3 p1(R * cphi, R * sphi, axes[1]->getMin());
133  Vector3 p0(R * cphi, R * sphi, axes[1]->getMax());
134  drawSegment(helper, transform * p0, transform * p1, gridConfig);
135  }
136  CylinderVolumeBounds cvb(R - 0.5 * thickness, R + 0.5 * thickness,
137  0.5 * thickness);
138  auto cvbOrientedSurfaces = cvb.orientedSurfaces();
139  for (auto z : zValues) {
140  for (const auto& cvbSf : cvbOrientedSurfaces) {
141  drawSurface(helper, *cvbSf.first, gctx,
142  Translation3(0., 0., z) * transform, gridRadConfig);
143  }
144  }
145 
146  } else if (binning[0] == binR and binning[1] == binPhi) {
147  double z = arrayExtent.medium(binZ) + gridConfig.offset;
148  auto rValues = axes[0]->getBinEdges();
149  auto phiValues = axes[1]->getBinEdges();
150  ViewConfig gridRadConfig = gridConfig;
151  gridRadConfig.nSegments = phiValues.size();
152  for (auto r : rValues) {
153  CylinderVolumeBounds cvb(r - 0.5 * thickness, r + 0.5 * thickness,
154  0.5 * thickness);
155  auto cvbOrientedSurfaces = cvb.orientedSurfaces();
156  for (const auto& cvbSf : cvbOrientedSurfaces) {
157  drawSurface(helper, *cvbSf.first, gctx,
158  Translation3(0., 0., z) * transform, gridRadConfig);
159  }
160  }
161  double rMin = axes[0]->getMin();
162  double rMax = axes[0]->getMax();
163  for (auto phi : phiValues) {
164  double cphi = std::cos(phi);
165  double sphi = std::sin(phi);
166  Vector3 p1(rMax * cphi, rMax * sphi, z);
167  Vector3 p0(rMin * cphi, rMin * sphi, z);
168  drawSegment(helper, transform * p0, transform * p1, gridConfig);
169  }
170  }
171  }
172 
173  if (not gridConfig.outputName.empty()) {
174  helper.write(joinPaths(outputDir, gridConfig.outputName));
175  helper.clear();
176  }
177 }
178 
180  const AbstractVolume& volume,
181  const GeometryContext& gctx,
182  const Transform3& transform,
183  const ViewConfig& viewConfig) {
184  auto bSurfaces = volume.boundarySurfaces();
185  for (const auto& bs : bSurfaces) {
186  drawSurface(helper, bs->surfaceRepresentation(), gctx, transform,
187  viewConfig);
188  }
189 }
190 
192  const Experimental::Portal& portal,
193  const GeometryContext& gctx,
194  const Transform3& transform,
195  const ViewConfig& connected,
196  const ViewConfig& disconnected) {
197  // color the portal based on if it contains two links(green)
198  // or one link(red)
199  auto surface = &(portal.surface());
200  auto links = &(portal.detectorVolumeUpdators());
201  if (links->size() == 2) {
202  drawSurface(helper, *surface, gctx, transform, connected);
203  } else {
204  drawSurface(helper, *surface, gctx, transform, disconnected);
205  }
206 }
207 
209  IVisualization3D& helper, const Experimental::DetectorVolume& volume,
210  const GeometryContext& gctx, const Transform3& transform,
211  const ViewConfig& connected, const ViewConfig& unconnected,
212  const ViewConfig& viewConfig) {
213  // draw the surfaces of the mother volume
214  for (auto surface : volume.surfaces()) {
215  drawSurface(helper, *surface, gctx, transform, viewConfig);
216  }
217 
218  // draw the envelope first
219  for (auto portal : volume.portals()) {
220  drawPortal(helper, *portal, gctx, transform, connected, unconnected);
221  }
222 
223  // recurse if there are subvolumes
224  for (auto subvolume : volume.volumes()) {
225  drawDetectorVolume(helper, *subvolume, gctx, transform, connected,
226  unconnected, viewConfig);
227  }
228 }
229 
231  IVisualization3D& helper, const Layer& layer, const GeometryContext& gctx,
232  const ViewConfig& layerConfig, const ViewConfig& sensitiveConfig,
233  const ViewConfig& gridConfig, const std::string& _outputDir) {
235  _outputDir == "." ? getWorkingDirectory() : _outputDir;
236 
237  if (layerConfig.visible) {
238  auto layerVolume = layer.representingVolume();
239  if (layerVolume != nullptr) {
240  drawVolume(helper, *layerVolume, gctx, Transform3::Identity(),
241  layerConfig);
242  } else {
243  const auto& layerSurface = layer.surfaceRepresentation();
244  drawSurface(helper, layerSurface, gctx, Transform3::Identity(),
245  layerConfig);
246  }
247  if (not layerConfig.outputName.empty()) {
248  helper.write(joinPaths(outputDir, layerConfig.outputName));
249  helper.clear();
250  }
251  }
252 
253  if (sensitiveConfig.visible or gridConfig.visible) {
254  auto surfaceArray = layer.surfaceArray();
255  if (surfaceArray != nullptr) {
256  drawSurfaceArray(helper, *surfaceArray, gctx, Transform3::Identity(),
257  sensitiveConfig, layerConfig, gridConfig, outputDir);
258  }
259  }
260 }
261 
263  IVisualization3D& helper, const TrackingVolume& tVolume,
264  const GeometryContext& gctx, const ViewConfig& containerView,
265  const ViewConfig& volumeView, const ViewConfig& layerView,
266  const ViewConfig& sensitiveView, const ViewConfig& gridView, bool writeIt,
267  const std::string& tag, const std::string& _outputDir) {
269  _outputDir == "." ? getWorkingDirectory() : _outputDir;
270  if (tVolume.confinedVolumes() != nullptr) {
271  const auto& subVolumes = tVolume.confinedVolumes()->arrayObjects();
272  for (const auto& tv : subVolumes) {
273  drawTrackingVolume(helper, *tv, gctx, containerView, volumeView,
274  layerView, sensitiveView, gridView, writeIt, tag,
275  outputDir);
276  }
277  }
278 
279  ViewConfig cConfig = containerView;
280  ViewConfig vConfig = volumeView;
281  ViewConfig lConfig = layerView;
282  ViewConfig sConfig = sensitiveView;
283  ViewConfig gConfig = gridView;
284  gConfig.nSegments = 8;
285 
286  ViewConfig vcConfig = cConfig;
287  std::string vname = tVolume.volumeName();
288  if (writeIt) {
289  std::vector<std::string> repChar = {"::" /*, "|", " ", "{", "}"*/};
290  // std::cout << "PRE: " << vname << std::endl;
291  for (const auto& rchar : repChar) {
292  while (vname.find(rchar) != std::string::npos) {
293  vname.replace(vname.find(rchar), rchar.size(), std::string("_"));
294  }
295  }
296  if (tVolume.confinedVolumes() == nullptr) {
297  vcConfig = vConfig;
298  vcConfig.outputName = vname + std::string("_boundaries") + tag;
299  } else {
300  std::stringstream vs;
301  vs << "Container";
302  std::vector<GeometryIdentifier::Value> ids{tVolume.geometryId().volume()};
303 
304  for (const auto* current = &tVolume; current->motherVolume() != nullptr;
305  current = current->motherVolume()) {
306  ids.push_back(current->motherVolume()->geometryId().volume());
307  }
308 
309  for (size_t i = ids.size() - 1; i < ids.size(); --i) {
310  vs << "_v" << ids[i];
311  }
312  vname = vs.str();
313  vcConfig.outputName = vname + std::string("_boundaries") + tag;
314  }
315  }
316 
317  auto bSurfaces = tVolume.boundarySurfaces();
318  for (const auto& bs : bSurfaces) {
319  drawSurface(helper, bs->surfaceRepresentation(), gctx,
320  Transform3::Identity(), vcConfig);
321  }
322  if (writeIt) {
323  std::string outputName = joinPaths(outputDir, vcConfig.outputName);
324  helper.write(outputName);
325  helper.clear();
326  }
327 
328  if (tVolume.confinedLayers() != nullptr) {
329  const auto& layers = tVolume.confinedLayers()->arrayObjects();
330  size_t il = 0;
331  for (const auto& tl : layers) {
332  if (writeIt) {
333  lConfig.outputName =
334  vname + std::string("_passives_l") + std::to_string(il) + tag;
335  sConfig.outputName =
336  vname + std::string("_sensitives_l") + std::to_string(il) + tag;
337  gConfig.outputName =
338  vname + std::string("_grids_l") + std::to_string(il) + tag;
339  }
340  drawLayer(helper, *tl, gctx, lConfig, sConfig, gConfig, outputDir);
341  ++il;
342  }
343  }
344 }
345 
347  const Vector3& start,
348  const Vector3& end, int arrows,
349  double arrowLength,
350  double arrowWidth,
351  const ViewConfig& viewConfig) {
352  double thickness = viewConfig.lineThickness;
353 
354  // Draw the parameter shaft and cone
355  auto direction = Vector3(end - start).normalized();
356  double hlength = 0.5 * Vector3(end - start).norm();
357 
358  auto unitVectors = makeCurvilinearUnitVectors(direction);
359  RotationMatrix3 lrotation;
360  lrotation.col(0) = unitVectors.first;
361  lrotation.col(1) = unitVectors.second;
362  lrotation.col(2) = direction;
363 
364  Vector3 lcenter = 0.5 * (start + end);
365  double alength = (thickness > 0.) ? arrowLength * thickness : 2.;
366  if (alength > hlength) {
367  alength = hlength;
368  }
369 
370  if (arrows == 2) {
371  hlength -= alength;
372  } else if (arrows != 0) {
373  hlength -= 0.5 * alength;
374  lcenter -= Vector3(arrows * 0.5 * alength * direction);
375  }
376 
377  // Line - draw a line
378  if (thickness > 0.) {
379  auto ltransform = Transform3::Identity();
380  ltransform.prerotate(lrotation);
381  ltransform.pretranslate(lcenter);
382 
383  auto lbounds = std::make_shared<CylinderBounds>(thickness, hlength);
384  auto line = Surface::makeShared<CylinderSurface>(ltransform, lbounds);
385 
386  drawSurface(helper, *line, GeometryContext(), Transform3::Identity(),
387  viewConfig);
388  } else {
389  helper.line(start, end, viewConfig.color);
390  }
391 
392  // Arrowheads - if configured
393  if (arrows != 0) {
394  double awith = thickness * arrowWidth;
395  double alpha = atan2(thickness * arrowWidth, alength);
396  auto plateBounds = std::make_shared<RadialBounds>(thickness, awith);
397 
398  if (arrows > 0) {
399  auto aetransform = Transform3::Identity();
400  aetransform.prerotate(lrotation);
401  aetransform.pretranslate(end);
402  // Arrow cone
403  auto coneBounds = std::make_shared<ConeBounds>(alpha, -alength, 0.);
404  auto cone = Surface::makeShared<ConeSurface>(aetransform, coneBounds);
405  drawSurface(helper, *cone, GeometryContext(), Transform3::Identity(),
406  viewConfig);
407  // Arrow end plate
408  auto aptransform = Transform3::Identity();
409  aptransform.prerotate(lrotation);
410  aptransform.pretranslate(Vector3(end - alength * direction));
411 
412  auto plate = Surface::makeShared<DiscSurface>(aptransform, plateBounds);
413  drawSurface(helper, *plate, GeometryContext(), Transform3::Identity(),
414  viewConfig);
415  }
416  if (arrows < 0 or arrows == 2) {
417  auto astransform = Transform3::Identity();
418  astransform.prerotate(lrotation);
419  astransform.pretranslate(start);
420 
421  // Arrow cone
422  auto coneBounds = std::make_shared<ConeBounds>(alpha, 0., alength);
423  auto cone = Surface::makeShared<ConeSurface>(astransform, coneBounds);
424  drawSurface(helper, *cone, GeometryContext(), Transform3::Identity(),
425  viewConfig);
426  // Arrow end plate
427  auto aptransform = Transform3::Identity();
428  aptransform.prerotate(lrotation);
429  aptransform.pretranslate(Vector3(start + alength * direction));
430 
431  auto plate = Surface::makeShared<DiscSurface>(aptransform, plateBounds);
432  drawSurface(helper, *plate, GeometryContext(), Transform3::Identity(),
433  viewConfig);
434  }
435  }
436 }
437 
439  const Vector3& start, const Vector3& end,
440  const ViewConfig& viewConfig) {
441  drawSegmentBase(helper, start, end, 0, 0., 0., viewConfig);
442 }
443 
445  IVisualization3D& helper, const Vector3& start, const Vector3& end,
446  double arrowLength, double arrowWidth, const ViewConfig& viewConfig) {
447  drawSegmentBase(helper, start, end, -1, arrowLength, arrowWidth, viewConfig);
448 }
449 
451  IVisualization3D& helper, const Vector3& start, const Vector3& end,
452  double arrowLength, double arrowWidth, const ViewConfig& viewConfig) {
453  drawSegmentBase(helper, start, end, 1, arrowLength, arrowWidth, viewConfig);
454 }
455 
457  const Vector3& start,
458  const Vector3& end,
459  double arrowLength, double arrowWidth,
460  const ViewConfig& viewConfig) {
461  drawSegmentBase(helper, start, end, 2, arrowLength, arrowWidth, viewConfig);
462 }