9#include <framework/logging/Logger.h>
10#include <framework/gearbox/GearDir.h>
11#include <geometry/utilities.h>
12#include <geometry/GeometryManager.h>
14#include <boost/algorithm/string.hpp>
15#include <boost/tuple/tuple.hpp>
18#include <G4LogicalVolume.hh>
19#include <G4VisAttributes.hh>
20#include <G4Polycone.hh>
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);
53 in >> std::hex >> colorValue;
54 if (in.fail()) size = 0;
57 colorValue = (colorValue << 4) + 15;
61 red = ((colorValue & 0xf000) >> 12) / 15.;
62 green = ((colorValue & 0x0f00) >> 8) / 15.;
63 blue = ((colorValue & 0x00f0) >> 4) / 15.;
64 alpha = ((colorValue & 0x000f) >> 0) / 15.;
67 colorValue = (colorValue << 8) + 255;
71 red = ((colorValue & 0xff000000) >> 24) / 255.;
72 green = ((colorValue & 0x00ff0000) >> 16) / 255.;
73 blue = ((colorValue & 0x0000ff00) >> 8) / 255.;
74 alpha = ((colorValue & 0x000000ff) >> 0) / 255.;
77 B2WARNING(
"Could not parse color string '" + colorString +
"'");
79 }
else if (colorString.substr(0, 3) ==
"rgb") {
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));
86 while (ws.find(in.peek()) != std::string::npos) in.get();
88 while (ws.find(in.peek()) != std::string::npos) in.get();
90 while (ws.find(in.peek()) != std::string::npos) in.get();
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));
97 return G4Colour(red, green, blue, alpha);
100 void setColor(G4LogicalVolume& volume,
const std::string& color)
102 auto* attr =
const_cast<G4VisAttributes*
>(volume.GetVisAttributes());
105 volume.SetVisAttributes(attr);
110 auto* attr =
const_cast<G4VisAttributes*
>(volume.GetVisAttributes());
112 attr->SetVisibility(visible);
113 volume.SetVisAttributes(attr);
118 if (!params)
return nullptr;
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();
125 B2ERROR(
"Polycone needs at least two planes");
128 std::vector<double> z(nPlanes, 0);
129 std::vector<double> rMin(nPlanes, 0);
130 std::vector<double> rMax(nPlanes, 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;
142 G4Polycone* polycone =
new G4Polycone(name, minPhi, dPhi, nPlanes, z.data(), rMin.data(), rMax.data());
149 using ZXPoint = std::pair<double, double>;
151 using PointList = std::list<ZXPoint>;
165 void subdivideSegments(
const PointList& points, PointList& segments)
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");
177 auto segStart = segments.begin();
178 auto segEnd = segStart;
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));
194 if (points.front().first < segments.front().first) {
195 segments.insert(segments.begin(), points.front());
197 if (points.back().first > segments.back().first) {
198 segments.insert(segments.end(), points.back());
207 PointList innerPoints;
208 PointList outerPoints;
210 innerPoints.push_back(ZXPoint(point.getLength(
"z") /
Unit::mm, point.getLength(
"x") /
Unit::mm));
213 outerPoints.push_back(ZXPoint(point.getLength(
"z") /
Unit::mm, point.getLength(
"x") /
Unit::mm));
217 subdivideSegments(innerPoints, outerPoints);
218 subdivideSegments(outerPoints, innerPoints);
219 minZ = innerPoints.front().first;
220 maxZ = outerPoints.front().first;
223 std::vector<double> z;
224 std::vector<double> rMin;
225 std::vector<double> rMax;
232 while (!(innerPoints.empty() && outerPoints.empty())) {
233 bool popInner =
false;
238 if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
239 boost::tie(innerZ, innerX) = innerPoints.front();
242 if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
243 boost::tie(outerZ, outerX) = outerPoints.front();
244 outerPoints.pop_front();
246 if (popInner) innerPoints.pop_front();
247 if (innerZ != outerZ) {
248 B2ERROR(
"createRotationSolid: Something is wrong, z values should be identical");
252 rMin.push_back(innerX);
253 rMax.push_back(outerX);
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());
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)
270 subdivideSegments(innerPoints, outerPoints);
271 subdivideSegments(outerPoints, innerPoints);
272 minZ = innerPoints.front().first;
273 maxZ = outerPoints.front().first;
276 std::vector<double> z;
277 std::vector<double> rMin;
278 std::vector<double> rMax;
285 while (!(innerPoints.empty() && outerPoints.empty())) {
286 bool popInner =
false;
292 if (!innerPoints.empty() && innerPoints.front().first <= outerPoints.front().first) {
293 boost::tie(innerZ, innerX) = innerPoints.front();
296 if (!outerPoints.empty() && outerPoints.front().first <= innerPoints.front().first) {
297 boost::tie(outerZ, outerX) = outerPoints.front();
298 outerPoints.pop_front();
300 if (popInner) innerPoints.pop_front();
301 if (innerZ != outerZ) {
302 B2ERROR(
"createRotationSolid: Something is wrong, z values should be identical");
311 int nPlanes = z.size();
312 double dPhi = maxPhi - minPhi;
313 return new G4Polycone(name, minPhi, dPhi, nPlanes, &z.front(), &rMin.front(), &rMax.front());
GearDir is the basic class used for accessing the parameter store.
static const double mm
[millimeters]
double getAngle(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard angle unit.
std::vector< GearDir > getNodes(const std::string &path="") const
Get vector of GearDirs which point to all the nodes the given path evaluates to.
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 ¶ms, double &minZ, double &maxZ)
Create Polycone Shape from XML Parameters.
G4Polycone * createRotationSolid(const std::string &name, const GearDir ¶ms, double &minZ, double &maxZ)
Create a solid by roating two polylines around the Z-Axis.
void setVisibility(G4LogicalVolume &volume, bool visible)
Helper function to quickly set the visibility of a given volume.
void setColor(G4LogicalVolume &volume, const std::string &color)
Set the color of a logical volume.
G4Colour parseColor(std::string colorString)
Parse a color string of the form "#rgb", "#rrggbb", "#rgba", "#rrggbbaa" or "rgb(r,...
Abstract base class for different kinds of events.