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