ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
output.cxx
Go to the documentation of this file.
1 //
2 // output.cpp
3 // Functions for writing output files.
4 //
5 // Author: Jens Wilberg, Lukas Aymans, Christoph Dalitz
6 // Date: 2018-08-30
7 // License: see ../LICENSE
8 //
9 
10 #include "output.h"
11 
12 #include "pointcloud.h" // for Point, PointCloud
13 #include <stdint.h>
14 
15 #include <cstdlib>
16 #include <iostream> // for operator<<, basic_ostream, basic_ostream<>::...
17 #include <memory> // for allocator_traits<>::value_type
18 #include <set>
19 #include <sstream> // IWYU pragma: keep
20 #include <string> // for char_traits, operator<<, string
21 #include <vector>
22 
23 //-------------------------------------------------------------------
24 // Computation of cluster colour
25 // The colour is computed from the index of the cluster and is returned
26 // as hex value.
27 //-------------------------------------------------------------------
28 unsigned long compute_cluster_colour(size_t cluster_index)
29 {
30  const double r = (double)((cluster_index * 23) % 19) / 18.0;
31  const double g = (double)((cluster_index * 23) % 7) / 6.0;
32  const double b = (double)((cluster_index * 23) % 3) / 2.0;
33  uint8_t r2 = (uint8_t)(r * 255);
34  uint8_t g2 = (uint8_t)(g * 255);
35  uint8_t b2 = (uint8_t)(b * 255);
36  unsigned long rgb_hex = (r2 << 16) | (g2 << 8) | b2;
37 
38  return rgb_hex;
39 }
40 
41 //-------------------------------------------------------------------
42 // Finds min and max Point of *cloud*
43 // the Points are returned in *min* and *max*.
44 //-------------------------------------------------------------------
45 void find_min_max_point(const PointCloud &cloud, Point &min, Point &max)
46 {
47  min = max = cloud[0];
48  for (std::vector<Point>::const_iterator p = cloud.begin(); p != cloud.end(); ++p) {
49  if (min.x > p->x) {
50  min.x = p->x;
51  } else if (max.x < p->x) {
52  max.x = p->x;
53  }
54  if (min.y > p->y) {
55  min.y = p->y;
56  } else if (max.y < p->y) {
57  max.y = p->y;
58  }
59  if (min.z > p->z) {
60  min.z = p->z;
61  } else if (max.z < p->z) {
62  max.z = p->z;
63  }
64  }
65 }
66 
67 //-------------------------------------------------------------------
68 // saves smoothen cloud as gnuplot script.
69 // The script is saved as file 'debug_smoothed.gnuplot' in the current
70 // working directory. It contains the original PointCloud *cloud* in
71 // black and the smoothed PointCloud *cloud_smooth* in red.
72 // *fname* is the name of the new file. The function returns false if
73 // an error occurred.
74 //-------------------------------------------------------------------
75 bool debug_gnuplot(const PointCloud &cloud, const PointCloud &cloud_smooth, const char *fname)
76 {
77  // saves cloud in gnuplot file
78  std::ofstream of(fname);
79  of << std::fixed; // set float style
80  bool is2d = cloud.is2d();
81  if (!of.is_open()) {
82  std::cerr << "[Error] could not save under '" << fname << std::endl;
83  return false;
84  }
85  // find ranges for each axis
86  Point min, max;
87  find_min_max_point(cloud, min, max);
88  // Write header
89  if (!is2d) {
90  // when max and min are the same, the script can't be ploted, so the range
91  // must be changed
92  if (max.x > min.x) {
93  of << "set xrange [" << min.x << ":" << max.x << "]\n";
94  } else {
95  of << "set xrange [" << (min.x - 1.0) << ":" << (max.x + 1.0) << "]\n";
96  }
97  if (max.y > min.y) {
98  of << "set yrange [" << min.y << ":" << max.y << "]\n";
99  } else {
100  of << "set yrange [" << (min.y - 1.0) << ":" << (max.y + 1.0) << "]\n";
101  }
102  if (max.z > min.z) {
103  of << "set zrange [" << min.z << ":" << max.z << "]\n ";
104  } else {
105  of << "set zrange [" << (min.z - 1.0) << ":" << (max.z + 1.0) << "]\n ";
106  }
107  of << "splot ";
108  } else {
109  // if we have 2D data we use plot instead of splot. For plot the header is
110  // not needed.
111  of << "plot ";
112  }
113 
114  of << "'-' with points lc 'black' title 'original', '-' with points lc "
115  "'red' title 'smoothed'\n";
116  for (PointCloud::const_iterator it = cloud.begin(); it != cloud.end(); ++it) {
117  of << it->x << " " << it->y;
118  if (!is2d)
119  of << " " << it->z;
120  of << std::endl;
121  }
122  of << "e\n";
123 
124  for (PointCloud::const_iterator it = cloud_smooth.begin(); it != cloud_smooth.end(); ++it) {
125  of << it->x << " " << it->y;
126  if (!is2d)
127  of << " " << it->z;
128  of << std::endl;
129  }
130  of << "e\npause mouse keypress\n";
131 
132  of.close();
133  return true;
134 }
135 
136 //-------------------------------------------------------------------
137 // saves a PointCloud *cloud* as csv file.
138 // The file is saved with the name *fname* under the current working
139 // directory. The function returns false if an error occurred.
140 //-------------------------------------------------------------------
141 bool cloud_to_csv(const PointCloud &cloud, const char *fname)
142 {
143  std::ofstream of(fname);
144  of << std::fixed; // set float style
145  bool is2d = cloud.is2d();
146  if (!of.is_open()) {
147  std::cerr << "[Error] could not save under '" << fname << std::endl;
148  return false;
149  }
150  of << "# x,y,z" << std::endl;
151  for (PointCloud::const_iterator it = cloud.begin(); it != cloud.end(); ++it) {
152  of << it->x << "," << it->y;
153  if (!is2d)
154  of << "," << it->z << std::endl;
155  }
156  of.close();
157  return true;
158 }
159 
160 //-------------------------------------------------------------------
161 // prints gnuplot script to stdout.
162 // rgb colours are created with the function *compute_cluster_colour*.
163 // The points of *cloud* are printed with the corresponding cluster/colour.
164 //-------------------------------------------------------------------
165 void clusters_to_gnuplot(const PointCloud &cloud, const std::vector<cluster_t> &clusters)
166 {
167  std::vector<Point> points = cloud;
168  std::ostringstream pointstream, header, noise, clstream;
169  std::string noiseheader = "";
170  bool is2d = cloud.is2d();
171  // set output format for floats
172  pointstream << std::fixed;
173  header << std::fixed;
174  noise << std::fixed;
175  // find ranges for each axis
176  Point min, max;
177  find_min_max_point(cloud, min, max);
178  // Write header
179  if (!is2d) {
180  // when max and min are the same, the script can't be ploted, so the range
181  // must be changed
182  if (max.x > min.x) {
183  header << "set xrange [" << min.x << ":" << max.x << "]\n";
184  } else {
185  header << "set xrange [" << (min.x - 1.0) << ":" << (max.x + 1.0) << "]\n";
186  }
187  if (max.y > min.y) {
188  header << "set yrange [" << min.y << ":" << max.y << "]\n";
189  } else {
190  header << "set yrange [" << (min.y - 1.0) << ":" << (max.y + 1.0) << "]\n";
191  }
192 
193  if (max.z > min.z) {
194  header << "set zrange [" << min.z << ":" << max.z << "]\nsplot ";
195  } else {
196  header << "set zrange [" << (min.z - 1.0) << ":" << (max.z + 1.0) << "]\nsplot ";
197  }
198  } else {
199  // if we have 2D data we use plot instead of splot. For plot the header is
200  // not needed.
201  header << "plot";
202  }
203 
204  // iterate over clusters
205  for (size_t cluster_index = 0; cluster_index < clusters.size(); ++cluster_index) {
206  const std::vector<size_t> &point_indices = clusters[cluster_index];
207  // if there are no points in the cluster, it is only contained in an overlap
208  // cluster
209  if (point_indices.size() == 0)
210  continue;
211  // add cluster header
212  unsigned long rgb_hex = compute_cluster_colour(cluster_index);
213  clstream << " '-' with points lc '#" << std::hex << rgb_hex;
214  std::set<size_t> cluster_ids = cloud[point_indices[0]].cluster_ids;
215  if (cluster_ids.size() > 1) {
216  clstream << "' title 'overlap ";
217  for (std::set<size_t>::const_iterator clid = cluster_ids.begin(); clid != cluster_ids.end(); ++clid) {
218  if (clid != cluster_ids.begin())
219  clstream << ";";
220  clstream << *clid;
221  }
222  } else {
223  clstream << "' title 'curve " << *cluster_ids.begin();
224  }
225  clstream << "',";
226 
227  // add points to script
228  for (std::vector<size_t>::const_iterator it = point_indices.begin(); it != point_indices.end(); ++it) {
229  const Point &point = cloud[*it];
230 
231  // remove current point from vector points
232  for (std::vector<Point>::iterator p = points.begin(); p != points.end(); p++) {
233  if (*p == point) {
234  points.erase(p);
235  break;
236  }
237  }
238  pointstream << point.x << " " << point.y;
239  if (!is2d)
240  pointstream << " " << point.z;
241  pointstream << std::endl;
242  }
243  pointstream << "e" << std::endl;
244  }
245  clstream << std::endl;
246 
247  // plot all points red which are not clustered
248  if (points.size() > 0) {
249  noiseheader = " '-' with points lc 'red' title 'noise',";
250  for (std::vector<Point>::iterator it = points.begin(); it != points.end(); ++it) {
251  noise << it->x << " " << it->y;
252  if (!is2d)
253  noise << " " << it->z;
254  noise << std::endl;
255  }
256  noise << "e" << std::endl;
257  }
258 
259  std::cout << header.str() << noiseheader << clstream.str() << noise.str() << pointstream.str()
260  << "pause mouse keypress\n";
261 }
262 
263 //-------------------------------------------------------------------
264 // saves the PointCloud *cloud* with clusters as csv file.
265 // The csv file has following form:
266 // x,y,z,clusterid
267 // or 2D:
268 // x,y,clusterid
269 //-------------------------------------------------------------------
270 void clusters_to_csv(const PointCloud &cloud)
271 {
272  bool is2d = cloud.is2d();
273  std::cout << std::fixed << "# Comment: curveID -1 represents noise\n# x, y, z, curveID\n";
274 
275  for (PointCloud::const_iterator it = cloud.begin(); it != cloud.end(); ++it) {
276  std::cout << it->x << "," << it->y << ",";
277  if (!is2d)
278  std::cout << it->z << ",";
279  if (it->cluster_ids.empty()) {
280  // Noise
281  std::cout << "-1\n";
282  } else {
283  for (std::set<size_t>::const_iterator it2 = it->cluster_ids.begin(); it2 != it->cluster_ids.end(); ++it2) {
284  if (it2 != it->cluster_ids.begin()) {
285  std::cout << ";";
286  }
287  std::cout << *it2;
288  }
289  std::cout << std::endl;
290  }
291  }
292 }
PointCloud::is2d
bool is2d() const
Definition: pointcloud.cxx:158
compute_cluster_colour
unsigned long compute_cluster_colour(size_t cluster_index)
Definition: output.cxx:28
Point::x
float x
Definition: main.cpp:72
Point
Definition: main.cpp:71
pointcloud.h
clusters_to_csv
void clusters_to_csv(const PointCloud &cloud)
Definition: output.cxx:270
PointCloud
Definition: pointcloud.h:60
debug_gnuplot
bool debug_gnuplot(const PointCloud &cloud, const PointCloud &cloud_smooth, const char *fname)
Definition: output.cxx:75
Point::y
float y
Definition: main.cpp:73
cloud_to_csv
bool cloud_to_csv(const PointCloud &cloud, const char *fname)
Definition: output.cxx:141
find_min_max_point
void find_min_max_point(const PointCloud &cloud, Point &min, Point &max)
Definition: output.cxx:45
clusters_to_gnuplot
void clusters_to_gnuplot(const PointCloud &cloud, const std::vector< cluster_t > &clusters)
Definition: output.cxx:165
output.h
Point::z
float z
Definition: main.cpp:74