11 #include <framework/logging/Logger.h>
12 #include <framework/gearbox/GearDir.h>
13 #include <geometry/utilities.h>
14 #include <geometry/GeometryManager.h>
16 #include <boost/algorithm/string.hpp>
17 #include <boost/tuple/tuple.hpp>
19 #include <G4Colour.hh>
20 #include <G4LogicalVolume.hh>
21 #include <G4VisAttributes.hh>
22 #include <G4Polycone.hh>
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);
52 in >> std::hex >> colorValue;
53 if (in.fail()) size = 0;
56 colorValue = (colorValue << 4) + 15;
60 red = ((colorValue & 0xf000) >> 12) / 15.;
61 green = ((colorValue & 0x0f00) >> 8) / 15.;
62 blue = ((colorValue & 0x00f0) >> 4) / 15.;
63 alpha = ((colorValue & 0x000f) >> 0) / 15.;
66 colorValue = (colorValue << 8) + 255;
70 red = ((colorValue & 0xff000000) >> 24) / 255.;
71 green = ((colorValue & 0x00ff0000) >> 16) / 255.;
72 blue = ((colorValue & 0x0000ff00) >> 8) / 255.;
73 alpha = ((colorValue & 0x000000ff) >> 0) / 255.;
76 B2WARNING(
"Could not parse color string '" + colorString +
"'");
78 }
else if (colorString.substr(0, 3) ==
"rgb") {
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));
85 while (ws.find(in.peek()) != std::string::npos) in.get();
87 while (ws.find(in.peek()) != std::string::npos) in.get();
89 while (ws.find(in.peek()) != std::string::npos) in.get();
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));
96 return G4Colour(red, green, blue, alpha);
99 void setColor(G4LogicalVolume& volume,
const std::string& color)
101 auto* attr =
const_cast<G4VisAttributes*
>(volume.GetVisAttributes());
104 volume.SetVisAttributes(attr);
109 auto* attr =
const_cast<G4VisAttributes*
>(volume.GetVisAttributes());
111 attr->SetVisibility(visible);
112 volume.SetVisAttributes(attr);
117 if (!params)
return nullptr;
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();
124 B2ERROR(
"Polycone needs at least two planes");
127 std::vector<double> z(nPlanes, 0);
128 std::vector<double> rMin(nPlanes, 0);
129 std::vector<double> rMax(nPlanes, 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;
141 G4Polycone* polycone =
new G4Polycone(name, minPhi, dPhi, nPlanes, z.data(), rMin.data(), rMax.data());
148 using ZXPoint = std::pair<double, double>;
150 using PointList = std::list<ZXPoint>;
164 void subdivideSegments(
const PointList& points, PointList& segments)
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");
176 auto segStart = segments.begin();
177 auto segEnd = segStart;
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));
193 if (points.front().first < segments.front().first) {
194 segments.insert(segments.begin(), points.front());
196 if (points.back().first > segments.back().first) {
197 segments.insert(segments.end(), points.back());
202 G4Polycone*
createRotationSolid(
const std::string& name,
const GearDir& params,
double& minZ,
double& maxZ)
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));
211 for (
const GearDir& point : params.getNodes(
"OuterPoints/point")) {
212 outerPoints.push_back(ZXPoint(point.getLength(
"z") /
Unit::mm, point.getLength(
"x") /
Unit::mm));
216 subdivideSegments(innerPoints, outerPoints);
217 subdivideSegments(outerPoints, innerPoints);
218 minZ = innerPoints.front().first;
219 maxZ = outerPoints.front().first;
222 std::vector<double> z;
223 std::vector<double> rMin;
224 std::vector<double> rMax;
231 while (!(innerPoints.empty() && outerPoints.empty())) {
232 bool popInner =
false;
237 if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
238 boost::tie(innerZ, innerX) = innerPoints.front();
241 if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
242 boost::tie(outerZ, outerX) = outerPoints.front();
243 outerPoints.pop_front();
245 if (popInner) innerPoints.pop_front();
246 if (innerZ != outerZ) {
247 B2ERROR(
"createRotationSolid: Something is wrong, z values should be identical");
251 rMin.push_back(innerX);
252 rMax.push_back(outerX);
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());
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)
269 subdivideSegments(innerPoints, outerPoints);
270 subdivideSegments(outerPoints, innerPoints);
271 minZ = innerPoints.front().first;
272 maxZ = outerPoints.front().first;
275 std::vector<double> z;
276 std::vector<double> rMin;
277 std::vector<double> rMax;
284 while (!(innerPoints.empty() && outerPoints.empty())) {
285 bool popInner =
false;
290 if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
291 boost::tie(innerZ, innerX) = innerPoints.front();
294 if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
295 boost::tie(outerZ, outerX) = outerPoints.front();
296 outerPoints.pop_front();
298 if (popInner) innerPoints.pop_front();
299 if (innerZ != outerZ) {
300 B2ERROR(
"createRotationSolid: Something is wrong, z values should be identical");
309 int nPlanes = z.size();
310 double dPhi = maxPhi - minPhi;
311 return new G4Polycone(name, minPhi, dPhi, nPlanes, &z.front(), &rMin.front(), &rMax.front());