Belle II Software  release-05-01-25
utilities.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <framework/logging/Logger.h>
12 #include <framework/gearbox/GearDir.h>
13 #include <geometry/utilities.h>
14 #include <geometry/GeometryManager.h>
15 
16 #include <boost/algorithm/string.hpp>
17 #include <boost/tuple/tuple.hpp>
18 
19 #include <G4Colour.hh>
20 #include <G4LogicalVolume.hh>
21 #include <G4VisAttributes.hh>
22 #include <G4Polycone.hh>
23 
24 #include <vector>
25 #include <limits>
26 #include <list>
27 
28 namespace Belle2 {
33  namespace geometry {
43  G4Colour parseColor(std::string colorString)
44  {
45  boost::to_lower(colorString);
46  double red(0), green(0), blue(0), alpha(0);
47  if (colorString[0] == '#') {
48  size_t size = colorString.size();
49  unsigned int colorValue;
50  std::stringstream in(colorString);
51  in.get();
52  in >> std::hex >> colorValue;
53  if (in.fail()) size = 0;
54  switch (size) {
55  case 4: //#rgb, add alpha since none was specified
56  colorValue = (colorValue << 4) + 15;
57  // and then continue with rgba case
58  [[fallthrough]];
59  case 5: //#rgba
60  red = ((colorValue & 0xf000) >> 12) / 15.;
61  green = ((colorValue & 0x0f00) >> 8) / 15.;
62  blue = ((colorValue & 0x00f0) >> 4) / 15.;
63  alpha = ((colorValue & 0x000f) >> 0) / 15.;
64  break;
65  case 7: //#rrggbb, add alpha since none was specified
66  colorValue = (colorValue << 8) + 255;
67  // and then continue with #rrggbbaa case
68  [[fallthrough]];
69  case 9: //#rrggbbaa
70  red = ((colorValue & 0xff000000) >> 24) / 255.;
71  green = ((colorValue & 0x00ff0000) >> 16) / 255.;
72  blue = ((colorValue & 0x0000ff00) >> 8) / 255.;
73  alpha = ((colorValue & 0x000000ff) >> 0) / 255.;
74  break;
75  default:
76  B2WARNING("Could not parse color string '" + colorString + "'");
77  }
78  } else if (colorString.substr(0, 3) == "rgb") {
79  //Parse value of the type rgb(1.0,1.0,1.0)
80  size_t startPos = colorString.find('(');
81  size_t stopPos = colorString.find(')');
82  std::string ws(" \t\r\n,");
83  std::stringstream in(colorString.substr(startPos + 1, stopPos - startPos - 1));
84  in >> red;
85  while (ws.find(in.peek()) != std::string::npos) in.get();
86  in >> green;
87  while (ws.find(in.peek()) != std::string::npos) in.get();
88  in >> blue;
89  while (ws.find(in.peek()) != std::string::npos) in.get();
90  in >> alpha;
91  red = std::min(1.0, std::max(0.0, red));
92  green = std::min(1.0, std::max(0.0, green));
93  blue = std::min(1.0, std::max(0.0, blue));
94  alpha = std::min(1.0, std::max(0.0, alpha));
95  }
96  return G4Colour(red, green, blue, alpha);
97  }
98 
99  void setColor(G4LogicalVolume& volume, const std::string& color)
100  {
101  auto* attr = const_cast<G4VisAttributes*>(volume.GetVisAttributes());
102  if (!attr) attr = GeometryManager::getInstance().newVisAttributes();
103  attr->SetColor(parseColor(color));
104  volume.SetVisAttributes(attr);
105  }
106 
107  void setVisibility(G4LogicalVolume& volume, bool visible)
108  {
109  auto* attr = const_cast<G4VisAttributes*>(volume.GetVisAttributes());
110  if (!attr) attr = GeometryManager::getInstance().newVisAttributes();
111  attr->SetVisibility(visible);
112  volume.SetVisAttributes(attr);
113  }
114 
115  G4Polycone* createPolyCone(const std::string& name, const GearDir& params, double& minZ, double& maxZ)
116  {
117  if (!params) return nullptr;
118 
119  double minPhi = params.getAngle("minPhi", 0);
120  double dPhi = params.getAngle("maxPhi", 2 * M_PI) - minPhi;
121  const std::vector<GearDir> planes = params.getNodes("Plane");
122  int nPlanes = planes.size();
123  if (nPlanes < 2) {
124  B2ERROR("Polycone needs at least two planes");
125  return nullptr;
126  }
127  std::vector<double> z(nPlanes, 0);
128  std::vector<double> rMin(nPlanes, 0);
129  std::vector<double> rMax(nPlanes, 0);
130  int index(0);
131  minZ = std::numeric_limits<double>::infinity();
132  maxZ = -std::numeric_limits<double>::infinity();
133  for (const GearDir& plane : planes) {
134  z[index] = plane.getLength("posZ") / Unit::mm;
135  minZ = std::min(minZ, z[index]);
136  maxZ = std::max(maxZ, z[index]);
137  rMin[index] = plane.getLength("innerRadius") / Unit::mm;
138  rMax[index] = plane.getLength("outerRadius") / Unit::mm;
139  ++index;
140  }
141  G4Polycone* polycone = new G4Polycone(name, minPhi, dPhi, nPlanes, z.data(), rMin.data(), rMax.data());
142  return polycone;
143  }
144 
145  //Use unnamed namespace to hide helper functions/definitions from outside
146  namespace {
148  using ZXPoint = std::pair<double, double>;
150  using PointList = std::list<ZXPoint>;
164  void subdivideSegments(const PointList& points, PointList& segments)
165  {
166  double lastZ = -std::numeric_limits<double>::infinity();
167  for (const ZXPoint p : points) {
168  if (p.first < lastZ) {
169  B2FATAL("createRotationSolid: Points have to be given with ascending z positions");
170  }
171  lastZ = p.first;
172  //Now go over all segments. If the segments cross the points z
173  //coordinate we know that we need a new segment. We calculate the x
174  //position of the segment and insert a new point at that position in
175  //the list of points
176  auto segStart = segments.begin();
177  auto segEnd = segStart;
178  ++segEnd;
179  for (; segEnd != segments.end(); ++segEnd) {
180  if ((p.first > segStart->first && p.first < segEnd->first) ||
181  (p.first < segStart->first && p.first > segEnd->first)) {
182  double dZ = segEnd->first - segStart->first;
183  double dX = segEnd->second - segStart->second;
184  double newX = segStart->second + dX * (p.first - segStart->first) / dZ;
185  segments.insert(segEnd, ZXPoint(p.first, newX));
186  }
187  segStart = segEnd;
188  }
189  }
190 
191  //Now make sure the polyline extend over the same z range by adding the
192  //first/last point of points when neccessary
193  if (points.front().first < segments.front().first) {
194  segments.insert(segments.begin(), points.front());
195  }
196  if (points.back().first > segments.back().first) {
197  segments.insert(segments.end(), points.back());
198  }
199  }
200  }
201 
202  G4Polycone* createRotationSolid(const std::string& name, const GearDir& params, double& minZ, double& maxZ)
203  {
204 
205  //Make a list of all the points (ZX coordinates)
206  PointList innerPoints;
207  PointList outerPoints;
208  for (const GearDir& point : params.getNodes("InnerPoints/point")) {
209  innerPoints.push_back(ZXPoint(point.getLength("z") / Unit::mm, point.getLength("x") / Unit::mm));
210  }
211  for (const GearDir& point : params.getNodes("OuterPoints/point")) {
212  outerPoints.push_back(ZXPoint(point.getLength("z") / Unit::mm, point.getLength("x") / Unit::mm));
213  }
214  //Subdivide the segments to have an x position for each z specified for
215  //either inner or outer boundary
216  subdivideSegments(innerPoints, outerPoints);
217  subdivideSegments(outerPoints, innerPoints);
218  minZ = innerPoints.front().first;
219  maxZ = outerPoints.front().first;
220 
221  //Now we create the array of planes needed for the polycone
222  std::vector<double> z;
223  std::vector<double> rMin;
224  std::vector<double> rMax;
225 
226  double innerZ{0};
227  double innerX{0};
228  double outerZ{0};
229  double outerX{0};
230  //We go through both lists until both are empty
231  while (!(innerPoints.empty() && outerPoints.empty())) {
232  bool popInner = false;
233  //We could have more than one point at the same z position for segments
234  //going directly along x. because of that we check that the z
235  //coordinates for inner and outer line are always the same, reusing one
236  //point if neccessary
237  if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
238  boost::tie(innerZ, innerX) = innerPoints.front();
239  popInner = true;
240  }
241  if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
242  boost::tie(outerZ, outerX) = outerPoints.front();
243  outerPoints.pop_front();
244  }
245  if (popInner) innerPoints.pop_front();
246  if (innerZ != outerZ) {
247  B2ERROR("createRotationSolid: Something is wrong, z values should be identical");
248  return nullptr;
249  }
250  z.push_back(innerZ);
251  rMin.push_back(innerX);
252  rMax.push_back(outerX);
253  }
254 
255  //Finally create the Polycone
256  int nPlanes = z.size();
257  double minPhi = params.getAngle("minPhi", 0);
258  double dPhi = params.getAngle("maxPhi", 2 * M_PI) - minPhi;
259  return new G4Polycone(name, minPhi, dPhi, nPlanes, &z.front(), &rMin.front(), &rMax.front());
260  }
261 
262  G4Polycone* createRotationSolid(const std::string& name,
263  std::list< std::pair<double, double> > innerPoints,
264  std::list< std::pair<double, double> > outerPoints,
265  double minPhi, double maxPhi, double& minZ, double& maxZ)
266  {
267  //Subdivide the segments to have an x position for each z specified for
268  //either inner or outer boundary
269  subdivideSegments(innerPoints, outerPoints);
270  subdivideSegments(outerPoints, innerPoints);
271  minZ = innerPoints.front().first;
272  maxZ = outerPoints.front().first;
273 
274  //Now we create the array of planes needed for the polycone
275  std::vector<double> z;
276  std::vector<double> rMin;
277  std::vector<double> rMax;
278 
279  double innerZ{0};
280  double innerX{0};
281  double outerZ{0};
282  double outerX{0};
283  //We go through both lists until both are empty
284  while (!(innerPoints.empty() && outerPoints.empty())) {
285  bool popInner = false;
286  //We could have more than one point at the same z position for segments
287  //going directly along x. because of that we check that the z
288  //coordinates for inner and outer line are always the same, reusing one
289  //point if neccessary
290  if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
291  boost::tie(innerZ, innerX) = innerPoints.front();
292  popInner = true;
293  }
294  if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
295  boost::tie(outerZ, outerX) = outerPoints.front();
296  outerPoints.pop_front();
297  }
298  if (popInner) innerPoints.pop_front();
299  if (innerZ != outerZ) {
300  B2ERROR("createRotationSolid: Something is wrong, z values should be identical");
301  return nullptr;
302  }
303  z.push_back(innerZ / Unit::mm);
304  rMin.push_back(innerX / Unit::mm);
305  rMax.push_back(outerX / Unit::mm);
306  }
307 
308  //Finally create the Polycone
309  int nPlanes = z.size();
310  double dPhi = maxPhi - minPhi;
311  return new G4Polycone(name, minPhi, dPhi, nPlanes, &z.front(), &rMin.front(), &rMax.front());
312 
313  }
314 
315 
316  }
318 } //Belle2 namespace
Belle2::geometry::setColor
void setColor(G4LogicalVolume &volume, const std::string &color)
Set the color of a logical volume.
Definition: utilities.cc:107
Belle2::geometry::GeometryManager::getInstance
static GeometryManager & getInstance()
Return a reference to the instance.
Definition: GeometryManager.cc:98
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::geometry::setVisibility
void setVisibility(G4LogicalVolume &volume, bool visible)
Helper function to quickly set the visibility of a given volume.
Definition: utilities.cc:115
Belle2::geometry::createRotationSolid
G4Polycone * createRotationSolid(const std::string &name, const GearDir &params, double &minZ, double &maxZ)
Create a solid by roating two polylines around the Z-Axis.
Definition: utilities.cc:210
Belle2::GearDir
GearDir is the basic class used for accessing the parameter store.
Definition: GearDir.h:41
Belle2::geometry::GeometryManager::newVisAttributes
G4VisAttributes * newVisAttributes()
Create an anonymous G4VisAttributes for an existing G4LogicalVolume.
Definition: GeometryManager.cc:374
Belle2::geometry::createPolyCone
G4Polycone * createPolyCone(const std::string &name, const GearDir &params, double &minZ, double &maxZ)
Create Polycone Shape from XML Parameters.
Definition: utilities.cc:123
Belle2::Unit::mm
static const double mm
[millimeters]
Definition: Unit.h:80
Belle2::geometry::parseColor
G4Colour parseColor(std::string colorString)
Parse a color string of the form #rgb, #rrggbb, #rgba, #rrggbbaa or rgb(r, g, b) and return a corresp...
Definition: utilities.cc:51