DASH  0.3.0
PatternVisualizer.h
1 #ifndef DASH__PATTERN_VISUALIZER_H
2 #define DASH__PATTERN_VISUALIZER_H
3 
4 #include <dash/dart/if/dart.h>
5 
6 #include <sstream>
7 #include <array>
8 #include <iomanip>
9 #include <string>
10 #include <utility>
11 #if 0
12 #define PATTERN_VISUALIZER_HSV
13 #endif
14 
15 #ifdef PATTERN_VISUALIZER_HSV
16 #include <dash/tools/Colorspace.h>
17 #endif
18 
19 namespace dash {
20 namespace tools {
21 
29 template<typename PatternT>
31 {
32 private:
34  typedef typename PatternT::index_type index_t;
35 
36  struct sizes {
37  int tileszx,
38  tileszy;
39  int blockszx,
40  blockszy;
41  int grid_width,
42  grid_height;
43  int grid_base;
44  int gridx,
45  gridy;
46  };
47 
48 private:
49  const PatternT & _pattern;
50 
51  int _tile_base_size;
52  int _block_base_size;
53  std::string _title;
54  std::string _descr;
55  int _fontsz_tiny,
56  _fontsz,
57  _fontsz_title;
58 
59  class RGB {
60  private:
61  unsigned _r, _g, _b;
62  public:
63  RGB(unsigned r, unsigned g, unsigned b) {
64  _r = r;
65  _g = g;
66  _b = b;
67  }
68  std::string hex() const {
69  std::ostringstream ss;
70  ss << "#" << std::hex << std::uppercase << std::setfill('0');
71  ss << std::setw(2) << _r << std::setw(2) << _g << std::setw(2) << _b;
72  return ss.str();
73  }
74  };
75 
76 public:
84  const PatternT& pat,
86  std::string title = "",
88  std::string descr = "")
89  : _pattern(pat)
90  , _title(std::move(title))
91  , _descr(std::move(descr))
92  {
93  _tile_base_size = 10;
94  _block_base_size = 26;
95  _fontsz_tiny = 9;
96  _fontsz = 10;
97  _fontsz_title = 12;
98  }
99 
100  PatternVisualizer() = delete;
101  PatternVisualizer(const self_t & other) = delete;
102 
107  void set_description(const std::string & str) {
108  _descr = str;
109  }
113  void set_title(const std::string & str) {
114  _title = str;
115  }
116 
122  std::ostream & os,
125  bool blocked_display = false,
127  std::array<index_t, PatternT::ndim()> coords = {},
129  int dimx = 1,
131  int dimy = 0) {
132  sizes sz;
133  sz.tileszx = sz.tileszy = _tile_base_size;
134  sz.blockszx = sz.blockszy = _block_base_size;
135  if(!blocked_display) {
136  sz.grid_width = _pattern.extent(dimx);
137  sz.grid_height = _pattern.extent(dimy);
138  sz.grid_base = _tile_base_size + 2;
139  sz.gridx = sz.gridy = sz.grid_base;
140  } else {
141  sz.grid_width = _pattern.blockspec().extent(dimx);
142  sz.grid_height = _pattern.blockspec().extent(dimy);
143  sz.grid_base = _block_base_size + 2;
144 
145  // Adjust tile sizes proportional to block regions:
146  float block_format = static_cast<float>(_pattern.blocksize(dimy)) /
147  static_cast<float>(_pattern.blocksize(dimx));
148  if (block_format < 1) {
149  block_format = 1.0 / block_format;
150  sz.blockszx *= block_format;
151  } else {
152  sz.blockszy *= block_format;
153  }
154  sz.gridx = sz.blockszx + 2;
155  sz.gridy = sz.blockszy + 2;
156  }
157 
158  std::string title = _title;
159  replace_all(title, "<", "&lt;");
160  replace_all(title, ">", "&gt;");
161 
162  os << "<svg xmlns=\"http://www.w3.org/2000/svg\"";
163  os << " xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
164 
165  // typeset title line
166  os << R"(<text x="10" y="15" )";
167  os << R"( fill="grey" font-size=")" << _fontsz_title << "\">";
168  os << title;
169  os << "</text>\n";
170 
171  // draw the pane, including axes and key
172  os << "<g transform=\"translate(10,30)\">\n";
173  draw_pane(os, blocked_display, sz, coords, dimx, dimy);
174  os << "</g>\n";
175 
176  os << "</svg>" << std::endl;
177  }
178 
184  void draw_pane(std::ostream & os, bool blocked_display,
185  const sizes & sz,
186  std::array<index_t, PatternT::ndim()> coords,
187  int dimx, int dimy) {
188  os << "<g transform=\"translate(10,10)\">" << std::endl;
189  draw_axes(os, sz, dimx, dimy);
190 
191  os << "<g transform=\"translate(4,4)\">" << std::endl;
192  if(!blocked_display) {
193  draw_local_blocks(os, sz, coords, dimx, dimy);
194  draw_tiles(os, sz, coords, dimx, dimy);
195  draw_local_memlayout(os, sz, dimx, dimy);
196  } else {
197  draw_blocks(os, sz, dimx, dimy);
198  }
199  os << "</g>" << std::endl;
200 
201  draw_key(os, sz, sz.grid_width * sz.gridx + 2*sz.grid_base, 0);
202  os << "</g>" << std::endl;
203  }
204 
208  void draw_axes(std::ostream & os,
209  const sizes & sz,
210  int dimx, int dimy,
211  int offsx = 0, int offsy = 0) {
212 
213  int startx = offsx;
214  int starty = offsy;
215  int lenx = sz.grid_width * sz.gridx + sz.grid_base;
216  int leny = sz.grid_height * sz.gridy + sz.grid_base;
217 
218  os << "<defs>\n";
219  os << R"(<marker id="arrowhead" orient="auto")";
220  os << R"( markerWidth="6" markerHeight="6")";
221  os << R"( refX="0" refY="0")";
222  os << " viewBox=\"-10 -15 30 30\">\n";
223  os << "<path d=\"";
224  os << "M " << -10 << " " << -15 << " ";
225  os << "L " << 20 << " " << 0 << " ";
226  os << "L " << -10 << " " << 15 << " ";
227  os << "L " << 0 << " " << 0 << " ";
228  os << "z ";
229  os << "\"";
230  os << " style=\"fill:#808080;stroke:#808080;stroke-width:1\"";
231  os << "/>";
232  os << "</marker>\n";
233  os << "</defs>\n";
234 
235  os << "<path d=\"";
236  os << "M " << startx << " " << starty << " ";
237  os << "h " << lenx << " ";
238  os << "\"";
239  os << " style=\"fill:none;stroke:#808080;stroke-width:1\"";
240  os << " marker-end=\"url(#arrowhead)\"";
241  os << "/>";
242 
243  os << "<text x=\"" << startx + lenx/3 << "\" y=\"" << starty - _fontsz/2 << "\" ";
244  os << R"( fill="grey" font-size=")" << _fontsz << "\" >";
245  os << "Dimension " << dimx << std::endl;
246  os << "</text>" << std::endl;
247 
248  os << "<path d=\"";
249  os << "M " << startx << " " << starty << " ";
250  os << "v " << leny << " ";
251  os << "\"";
252  os << " style=\"fill:none;stroke:#808080;stroke-width:1\"";
253  os << " marker-end=\"url(#arrowhead)\"";
254  os << "/>";
255 
256  os << "<text x=\"" << startx - _fontsz/2 << "\" y=\"" << starty + leny/3 << "\" ";
257  os << " transform=\"rotate(-90," << startx - _fontsz/2 << "," << starty + leny/3 << ")\" ";
258  os << R"( fill="grey" font-size=")" << _fontsz << "\" >";
259  os << "Dimension " << dimy << std::endl;
260  os << "</text>" << std::endl;
261  }
262 
266  void draw_key(std::ostream & os,
267  const sizes & sz,
268  int offsx = 0, int offsy = 0) {
269  int startx, starty;
270 
271  startx = offsx;
272  for (int unit = 0; unit < _pattern.num_units(); unit++) {
273  startx = offsx;
274  starty = offsy + (unit * (sz.tileszy + 2));
275  os << "<rect x=\"" << startx << "\" y=\"" << starty << "\" ";
276  os << "height=\"" << sz.tileszy << "\" width=\"" << sz.tileszx << "\" ";
277  os << tilestyle(unit);
278  os << "> ";
279  os << "</rect>" << std::endl;
280 
281  starty += sz.tileszy - 2;
282  startx += sz.tileszx + 1;
283  os << "<text x=\"" << startx << "\" y=\"" << starty << "\" ";
284  os << R"( fill="grey" font-size=")" << _fontsz << "\"";
285  os << " >";
286  os << "Unit " << unit << std::endl;
287  os << "</text>" << std::endl;
288  }
289  }
290 
294  void draw_tiles(std::ostream & os,
295  const sizes & sz,
296  std::array<index_t, PatternT::ndim()> coords,
297  int dimx, int dimy) {
298  for (int i = 0; i < _pattern.extent(dimx); i++) {
299  for (int j = 0; j < _pattern.extent(dimy); j++) {
300 
301  os << "<rect x=\"" << (i * sz.gridx) << "\" y=\"" << (j * sz.gridy) << "\" ";
302  os << "height=\"" << sz.tileszy << "\" width=\"" << sz.tileszx << "\" ";
303 
304  coords[dimx] = i;
305  coords[dimy] = j;
306 
307  auto unit = _pattern.unit_at(coords);
308  auto loffs = _pattern.at(coords);
309 
310  os << tilestyle(unit);
311  os << " tooltip=\"enable\" > ";
312  os << " <title>Elem: (" << j << "," << i <<"),";
313  os << " Unit " << unit;
314  os << " Local offs. " << loffs;
315  os << "</title>";
316 
317  //os << "<!-- i=" << i << " j=" << j << "--> ";
318  os << "</rect>" << std::endl;
319  }
320  }
321  }
322 
326  void draw_blocks(std::ostream & os,
327  const sizes & sz,
328  int dimx, int dimy) {
329  std::array<index_t, PatternT::ndim()> block_coords;
330  std::array<index_t, PatternT::ndim()> block_begin_coords;
331  auto blockspec = _pattern.blockspec();
332  for (int i = 0; i < blockspec.extent(dimx); i++) {
333  for (int j = 0; j < blockspec.extent(dimy); j++) {
334  block_coords[dimx] = i;
335  block_coords[dimy] = j;
336  auto block_idx = _pattern.blockspec().at(block_coords);
337  auto block = _pattern.block(block_idx);
338  block_begin_coords[dimx] = block.offset(dimx);
339  block_begin_coords[dimy] = block.offset(dimy);
340  auto unit = _pattern.unit_at(block_begin_coords);
341 
342  int i_grid = i * sz.gridx;
343  int j_grid = j * sz.gridy;
344 
345  os << "<rect x=\"" << i_grid << "\" y=\"" << j_grid << "\" ";
346  os << "height=\"" << sz.blockszy << "\" width=\"" << sz.blockszx << "\" ";
347  os << tilestyle(unit);
348  os << "> ";
349  os << "<!-- i=" << i << " j=" << j << "--> ";
350  os << "</rect>" << std::endl;
351  }
352  }
353  }
354 
358  void draw_local_blocks(std::ostream & os,
359  const sizes & sz,
360  std::array<index_t, PatternT::ndim()> coords,
361  int dimx, int dimy) {
362 
363  std::array<index_t, PatternT::ndim()> block_coords = coords;
364  std::array<index_t, PatternT::ndim()> block_begin_coords = coords;
365 
366  auto blockspec = _pattern.blockspec();
367 
368  for (int i = 0; i < blockspec.extent(dimx); i++) {
369  for (int j = 0; j < blockspec.extent(dimy); j++) {
370 
371  block_coords[dimx] = i;
372  block_coords[dimy] = j;
373  auto block_idx = _pattern.blockspec().at(block_coords);
374  auto block = _pattern.block(block_idx);
375 
376  block_begin_coords[dimx] = block.offset(dimx);
377  block_begin_coords[dimy] = block.offset(dimy);
378  auto unit = _pattern.unit_at(block_begin_coords);
379 
380  if( unit==0 ) {
381  int i_grid = block.offset(dimx)*sz.gridx - 1;
382  int j_grid = block.offset(dimy)*sz.gridy - 1;
383 
384  int width = (block.extent(dimx)-1)*sz.gridx + sz.tileszx + 2;
385  int height = (block.extent(dimy)-1)*sz.gridy + sz.tileszy + 2;
386 
387  os << "<rect x=\"" << i_grid << "\" y=\"" << j_grid << "\" ";
388  os << "height=\"" << height << "\" width=\"" << width << "\" ";
389  os << "style=\"fill:#999999;stroke-width:0\" >";
390  os << "</rect>" << std::endl;
391  }
392  }
393  }
394  }
395 
399  void draw_local_memlayout(std::ostream & os,
400  const sizes & sz,
401  int dimx, int dimy) {
402  int startx, starty;
403  int endx, endy;
404 
405  startx = starty = 0;
406  for ( auto offset = 0; offset < _pattern.local_size(); offset++ ) {
407  auto coords = _pattern.coords(_pattern.global(offset));
408 
409  endx = (coords[dimx] * sz.gridx) + sz.tileszx / 2;
410  endy = (coords[dimy] * sz.gridy) + sz.tileszy / 2;
411 
412  if ( startx > 0 && starty > 0 ) {
413  os << "<line x1=\"" << startx << "\" y1=\"" << starty << "\"";
414  os << " x2=\"" << endx << "\" y2=\"" << endy << "\"";
415  os << " style=\"stroke:#E0E0E0;stroke-width:1\"/>";
416  os << " <!-- (" << offset << ") -->";
417  os << std::endl;
418  }
419 
420  os << "<circle cx=\"" << endx << "\" cy=\"" << endy << R"(" r="1.5" )";
421  os << " style=\"stroke:#E0E0E0;stroke-width:1;fill:#E0E0E0\" />";
422  os << std::endl;
423 
424  startx = endx;
425  starty = endy;
426  }
427 
428  }
429 
430 private:
431  #ifndef PATTERN_VISUALIZER_HSV
432  RGB color(dart_unit_t unit) {
433  unsigned r = 0, g = 0, b = 0;
434  switch (unit % 8) {
435  case 0:
436  r = 0x00;
437  g = 0x72;
438  b = 0xBD;
439  break;
440  case 1:
441  r = 0xD9;
442  g = 0x53;
443  b = 0x19;
444  break;
445  case 2:
446  r = 0xEB;
447  g = 0xB1;
448  b = 0x20;
449  break;
450  case 3:
451  r = 0x7E;
452  g = 0x2F;
453  b = 0x8E;
454  break;
455  case 4:
456  r = 0x77;
457  g = 0xAC;
458  b = 0x30;
459  break;
460  case 5:
461  r = 0x4D;
462  g = 0xBE;
463  b = 0xEE;
464  break;
465  case 6:
466  r = 0xA2;
467  g = 0x14;
468  b = 0x2F;
469  break;
470  case 7:
471  r = 0x33;
472  g = 0x6F;
473  b = 0x45;
474  break;
475  }
476 
477  r += 20 * (unit / 8);
478  g += 20 * (unit / 8);
479  b += 20 * (unit / 8);
480 
481  return RGB(r % 255, g % 255, b % 255);
482  }
483  #else
484  RGB color(dart_unit_t unit) {
485  float min = 0;
486  float max = _pattern.num_units();
487  float nx = _pattern.teamspec().extent(1);
488  float ny = _pattern.teamspec().extent(0);
489  auto unit_coord = _pattern.teamspec().coords(unit);
490 
491  // unit id to color wavelength:
492  float unit_h_perc = static_cast<float>(unit) / max;
493  float unit_s_perc = static_cast<float>(unit_coord[0]) / ny;
494  float unit_v_perc = static_cast<float>(unit_coord[1]) / nx;
495 
497  hsv.h = 360.0 * unit_h_perc;
498  hsv.s = 0.5 + 0.5 * unit_s_perc;
499  hsv.v = 0.5 + 0.4 * unit_v_perc;
500 
501  auto rgb = dash::tools::color::hsv2rgb(hsv);
502  int r = static_cast<int>(rgb.r * 255);
503  int g = static_cast<int>(rgb.g * 255);
504  int b = static_cast<int>(rgb.b * 255);
505 
506  return RGB(r,g,b);
507  }
508  #endif
509 
510  std::string tilestyle(dart_unit_t unit)
511  {
512  std::ostringstream ss;
513  ss << "style=\"fill:" << color(unit).hex() << ";";
514  ss << "stroke-width:0\"";
515  return ss.str();
516  }
517 
518  bool replace_string(std::string & str,
519  const std::string & from,
520  const std::string & to)
521  {
522  size_t start_pos = str.find(from);
523  if (start_pos == std::string::npos) {
524  return false;
525  }
526  str.replace(start_pos, from.length(), to);
527  return true;
528  }
529 
530  bool replace_all(std::string & str,
531  const std::string & from,
532  const std::string & to)
533  {
534  while (replace_string(str, from, to)) {};
535  return true;
536  }
537 };
538 
539 } // namespace tools
540 } // namespace dash
541 
542 #endif // DASH__PATTERN_VISUALIZER_H
void draw_pane(std::ostream &os, bool blocked_display, const sizes &sz, std::array< index_t, PatternT::ndim()> coords, int dimx, int dimy)
Draws a pane (svg group) containing axes, key, tiles/blocks For the non blocked display (tiles) the l...
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
void draw_axes(std::ostream &os, const sizes &sz, int dimx, int dimy, int offsx=0, int offsy=0)
Draws the axes labeled with their dedicated dimension.
int32_t dart_unit_t
Data type for storing a unit ID.
Definition: dart_types.h:154
Reduce operands to their maximum value.
Definition: Operation.h:144
void set_description(const std::string &str)
Sets a description for the pattern.
void draw_pattern(std::ostream &os, bool blocked_display=false, std::array< index_t, PatternT::ndim()> coords={}, int dimx=1, int dimy=0)
Outputs the pattern as a svg over the given output stream.
PatternVisualizer(const PatternT &pat, std::string title="", std::string descr="")
Constructs the Pattern Visualizer with a pattern instance.
void draw_tiles(std::ostream &os, const sizes &sz, std::array< index_t, PatternT::ndim()> coords, int dimx, int dimy)
Draws the seperate tiles of the pattern.
Take a generic pattern instance and visualize it as an SVG image.
constexpr dim_t ndim(const DimensionalType &d)
Definition: Dimensional.h:56
void set_title(const std::string &str)
Sets the title displayed above the pattern.
void draw_local_blocks(std::ostream &os, const sizes &sz, std::array< index_t, PatternT::ndim()> coords, int dimx, int dimy)
Draws the local blocks of the current unit (usually unit 0)
void draw_key(std::ostream &os, const sizes &sz, int offsx=0, int offsy=0)
Draws a list of units with their matching color.
see https://en.cppreference.com/w/cpp/feature_test for recommended feature tests
Definition: cstddef.h:8
void draw_local_memlayout(std::ostream &os, const sizes &sz, int dimx, int dimy)
Draws the memory layout for the current unit (usually unit 0)
void draw_blocks(std::ostream &os, const sizes &sz, int dimx, int dimy)
Draws the blocks of the pattern.
constexpr auto block(OffsetT block_idx, const ViewType &view) -> typename std::enable_if<(!dash::view_traits< ViewType >::is_local::value), ViewBlockMod< ViewType > >::type
Blocks view from global view.
Definition: Chunked.h:49