VPTissue Reference Manual
MeshDrawer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "MeshDrawer.h"
21 
22 #include "ArrowItem.h"
23 #include "NodeItem.h"
24 #include "WallItem.h"
25 
26 #include "bio/BoundaryType.h"
27 #include "bio/Cell.h"
28 #include "bio/Mesh.h"
29 #include "bio/Node.h"
30 #include "bio/ReduceCellWalls.h"
31 #include "bio/Wall.h"
33 #include "sim/CoreData.h"
34 #include "sim/SimInterface.h"
35 #include "util/misc/StringUtils.h"
37 
38 #include <QApplication>
39 #include <QGraphicsItem>
40 #include <QGraphicsPolygonItem>
41 #include <QToolTip>
42 
43 #include <cctype>
44 #include <functional>
45 #include <vector>
46 
47 using namespace std;
48 using namespace SimPT_Sim::Util;
49 using namespace SimPT_Sim;
50 
51 static inline array<double, 3> PINdir(Cell* here, Cell* , Wall* w)
52 {
53  assert( (w->GetC1() == here || w->GetC2() == here) && "Error in cell <-> wall!" );
54  const double trans = (w->GetC1() == here) ? w->GetTransporters1(1U) : w->GetTransporters2(1U);
55  return trans * w->GetInfluxVector(here);
56 }
57 
58 namespace SimPT_Shell {
59 
60 MeshDrawer::MeshDrawer() : m_preferences(make_shared<prefs_type>()) {}
61 
62 MeshDrawer::MeshDrawer(const std::shared_ptr<prefs_type>& p) : m_preferences(p) {}
63 
64 void MeshDrawer::Draw(shared_ptr<SimPT_Sim::SimInterface> sim, QGraphicsScene* scene)
65 {
66  const auto mesh = sim->GetCoreData().m_mesh.get();
67  const ptree& parameters = *sim->GetCoreData().m_parameters;
68 
69  const auto model_group = parameters.get<string>("model.group", "");
70  const auto factory = ComponentFactoryProxy::Create(model_group);
71  const auto cell_colorizer = factory->CreateCellColor(m_preferences->m_cell_color, parameters);
72 
73  const auto& nodes = mesh->GetNodes();
74  const auto loop_nodes = [&nodes](function<void(Node*)> draw) {
75  for (const auto& n : nodes) {draw(n);}
76  };
77 
78  const auto& walls = mesh->GetWalls();
79  const auto loop_walls = [&walls](function<void(Wall*)> draw) {
80  for (auto const& w : walls) {draw(w);}
81  };
82 
83  const auto& cells = mesh->GetCells();
84  const auto loop_cells = [&cells](function<void(Cell*)> draw) {
85  for (auto c : cells) {draw(c);}
86  };
87  const auto loop_nb_cells = [&cells](function<void(Cell*)> draw) {
88  for (auto c : cells) {if (c->GetBoundaryType() == BoundaryType::None) {draw(c);}}
89  };
90 
91  const auto cell_draw_with_tooltip = [&](Cell* cell) {
92  const auto& nodes = cell->GetNodes();
93  QPolygonF pa(nodes.size());
94  int cc = 0;
95  const unsigned int num_chem = mesh->GetNumChemicals();
96 
97  // Build QGraphicsPolygonItem (via CellItem)
98  for (auto const& n : nodes) {
99  auto pos = (m_preferences->m_mesh_offset + *n) * m_preferences->m_mesh_magnification;
100  pa[cc++] = QPoint(static_cast<int>(pos[0]), static_cast<int>(pos[1]));
101  }
102  const auto c = cell_colorizer(cell);
103  QColor cell_color = QColor::fromRgbF(get<0>(c), get<1>(c), get<2>(c));
104 
105  auto p = scene->addPolygon(pa, m_preferences->m_outline_width >= 0 ?
106  QPen(QColor(m_preferences->m_cell_outline_color.c_str()), m_preferences->m_outline_width) : QPen(Qt::NoPen),
107  cell_color);
108  p->setZValue(1);
109 
110  // Build tool tip for the current cell
111  // General information of current cell
112  QString tool_tip = QString("Cell: %1, type: %2 \n").arg(cell->GetIndex()).arg(cell->GetCellType());
113  tool_tip += QString("Chemicals (count=%1): ").arg(num_chem);
114  for (unsigned int i = 0; i < num_chem; i++) {
115  tool_tip += QString("%1 ").arg((cell->GetChemical(i))/(cell->GetArea()));
116  }
117  QString bt = QString::fromStdString(ToString(cell->GetBoundaryType()));
118  tool_tip += QString("\nArea: %1\nCircumference: %2\nBoundary type: %3")
119  .arg(cell->GetArea()).arg(cell->GetCircumference()).arg(bt);
120 
121  // Node information of current cell
122  QString nodelist = "Node_list = { ";
123  for (auto const& n : nodes) {
124  nodelist += QString("%1 ").arg(n->GetIndex());
125  }
126  nodelist += " } ";
127  tool_tip += "\nNodes: " + nodelist;
128 
129  // Wall information of current cell
130  QString walllist = "Wall_list = { ";
131  for (auto const& w : cell->GetWalls()) {
132  walllist += QString("%1 ").arg(w->GetIndex());
133  }
134  walllist += " } ";
135  tool_tip += "\nWalls: " + walllist;
136 
137  p->setToolTip(tool_tip);
138 
139  // Actual drawing
140  p->show();
141  };
142 
143  const auto cell_draw = [&](Cell* cell) {
144  const auto& nodes = cell->GetNodes();
145  QPolygonF pa(nodes.size());
146  int cc = 0;
147 
148  // Build QGraphicsPolygonItem
149  for (auto const& n : nodes) {
150  auto pos = (m_preferences->m_mesh_offset + *n) * m_preferences->m_mesh_magnification;
151  pa[cc++] = QPoint(static_cast<int>(pos[0]), static_cast<int>(pos[1]));
152  }
153  const auto c = cell_colorizer(cell);
154  QColor cell_color = QColor::fromRgbF(get<0>(c), get<1>(c), get<2>(c));
155 
156  auto p = scene->addPolygon(pa, m_preferences->m_outline_width >= 0 ?
157  QPen(QColor(m_preferences->m_cell_outline_color.c_str()), m_preferences->m_outline_width) : QPen(Qt::NoPen),
158  cell_color);
159  p->setZValue(1);
160 
161  // Actual drawing
162  p->show();
163  };
164 
165  const auto cell_draw_center = [&](Cell* cell) {
166  QRectF rect(-1*m_preferences->m_node_magnification, -1*m_preferences->m_node_magnification,
167  2*m_preferences->m_node_magnification, 2*m_preferences->m_node_magnification);
168  auto disk = scene->addEllipse(rect, QPen(), QColor("forest green"));
169  disk->setZValue(5);
170  disk->show();
171  const auto pos = (m_preferences->m_mesh_offset
172  + cell->GetCentroid()) * m_preferences->m_mesh_magnification;
173  disk->setPos(pos[0], pos[1]);
174  };
175 
176  const auto cell_draw_fluxes = [&](Cell* cell) {
177  // get the mean flux through this cell
178  auto reduce_cell_walls = [](Cell* cell){
179  std::array<double,3> sum {{0.0, 0.0, 0.0}};
180  for (auto const& wall : cell->GetWalls()) {
181  sum += (wall->GetC1() == cell) ?
182  PINdir(wall->GetC1(), wall->GetC2(), wall)
183  : PINdir(wall->GetC2(), wall->GetC1(), wall);
184  }
185  return sum;
186  };
187  const auto vec_flux = Normalize(reduce_cell_walls(cell));
188 
189  ArrowItem* arrow = new ArrowItem();
190  scene->addItem(arrow);
191  const auto centroid = cell->GetCentroid();
192  const auto from = (m_preferences->m_mesh_offset + centroid
193  - vec_flux * 0.5 * m_preferences->m_arrow_size) * m_preferences->m_mesh_magnification;
194  const auto to = (m_preferences->m_mesh_offset + centroid
195  + vec_flux * 0.5 * m_preferences->m_arrow_size) * m_preferences->m_mesh_magnification;
196 
197  arrow->setPen( QPen(QColor(m_preferences->m_arrow_color.c_str()), m_preferences->m_outline_width));
198  arrow->setLine(from[0], from[1], to[0], to[1]);
199  arrow->setZValue(20);
200  arrow->show();
201  };
202 
203  const auto cell_draw_text = [&](Cell* cell, const QString& text) {
204  const auto pos = (m_preferences->m_mesh_offset
205  + cell->GetCentroid()) * m_preferences->m_mesh_magnification;
206  auto ctext = scene->addText(text, QFont( "Helvetica",
207  m_preferences->m_cell_number_size, QFont::Bold));
208  ctext->setDefaultTextColor( QColor(m_preferences->m_text_color.c_str()) );
209  ctext->setZValue(20);
210  ctext->show();
211  ctext->setPos(pos[0],pos[1]);
212  };
213 
214  const auto cell_draw_index = [&](Cell* cell) {
215  cell_draw_text(cell, QString::number(cell->GetIndex()));
216  };
217 
218  const auto cell_draw_axis = [&](Cell* cell) {
219  const auto& tup = cell->GetGeoData().GetEllipseAxes();
220  const auto long_axis = Normalize(get<1>(tup));
221  const auto short_axis = Orthogonalize(long_axis);
222  const auto centroid = cell->GetCentroid();
223  const auto delta = 0.5 * get<2>(tup) * short_axis;
224  const auto from = (m_preferences->m_mesh_offset + centroid - delta) * m_preferences->m_mesh_magnification;
225  const auto to = (m_preferences->m_mesh_offset + centroid + delta) * m_preferences->m_mesh_magnification;
226 
227  auto line = scene->addLine(QLineF(from[0], from[1], to[0], to[1]),
228  QPen(QColor(m_preferences->m_arrow_color.c_str()),2));
229  line->setZValue(2);
230  line->setZValue(10);
231  line->show();
232  };
233 
234  const auto node_draw = [&](Node* node) {
235  const auto pos = (m_preferences->m_mesh_offset + *node) * m_preferences->m_mesh_magnification;
236  NodeItem* item = new NodeItem(node, m_preferences->m_node_magnification);
237  scene->addItem(item);
238  item->setColor();
239  item->setZValue(5);
240  item->show();
241  item->setPos(pos[0], pos[1]);
242  };
243 
244  const auto node_draw_index = [&](Node* node) {
245  const auto pos = (m_preferences->m_mesh_offset + *node) * m_preferences->m_mesh_magnification;
246  auto number = scene->addSimpleText(QString::number(node->GetIndex()),
247  QFont( "Helvetica", m_preferences->m_node_number_size, QFont::Bold));
248  //QGraphicsSimpleTextItem* number = new QGraphicsSimpleTextItem ( QString::number(node->GetIndex()), 0, scene);
249  //number->setFont( QFont( "Helvetica", m_preferences->m_node_number_size, QFont::Bold) );
250  number->setPen( QPen (m_preferences->m_text_color.c_str()) );
251  number->setZValue(20);
252  number->show();
253  number->setPos(pos[0], pos[1]);
254  };
255 
256  const auto node_draw_with_tooltip = [&](Node* node) {
257  // Build tool tip for the current node
258  const auto pos = (m_preferences->m_mesh_offset + *node) * m_preferences->m_mesh_magnification;
259  NodeItem* item = new NodeItem(node, m_preferences->m_node_magnification);
260  scene->addItem(item);
261  item->setColor();
262  item->setZValue(5);
263  item->show();
264  item->setPos(pos[0], pos[1]);
265 
266  // General information of current node
267  QString tool_tip = QString("Node: %1\n").arg(node->GetIndex());
268  tool_tip += QString("Fixed: %1\n").arg(node->IsFixed());
269  tool_tip += QString("Sam: %1\n").arg(node->IsSam());
270 
271 
272  // Cell information of current node
273  tool_tip += "Cells: Cell_list = { ";
274  for (auto const& c : mesh->GetCells()) {
275  if (std::find_if(c->GetNodes().begin(), c->GetNodes().end(),
276  [&node](Node* n){return n->GetIndex() == node->GetIndex();}) != c->GetNodes().end()) {
277  tool_tip += QString("%1 ").arg(c->GetIndex());
278  }
279  }
280  tool_tip += "}\n";
281 
282  // Wall information of current node
283  tool_tip += "Walls: Wall_list = { ";
284  for (auto const& w : mesh->GetNodeOwningWalls(node)) {
285  tool_tip += QString("%1 ").arg(w->GetIndex());
286  }
287  tool_tip += " }";
288 
289  item->setToolTip(tool_tip);
290 
291  // Actual drawing
292  item->show();
293  };
294 
295  const auto wall_draw = [&](Wall* wall) {
296  // Each wall connects two cells and needs to be visualized inside both cells.
297  // Therefore, each wall needs two WallItems for visualization.
298  WallItem* wi1 = new WallItem(wall, 1, scene, m_preferences->m_outline_width,
299  m_preferences->m_mesh_magnification, m_preferences->m_mesh_offset);
300  WallItem* wi2 = new WallItem(wall, 2, scene, m_preferences->m_outline_width,
301  m_preferences->m_mesh_magnification, m_preferences->m_mesh_offset);
302  scene->addItem(wi1);
303  scene->addItem(wi2);
304  wi1->show();
305  wi2->show();
306  };
307 
308  const auto wall_draw_with_tooltip = [&](Wall* wall) {
309  // Each wall connects two cells and needs to be visualized inside both cells.
310  // Therefore, each wall needs two WallItems for visualization.
311  WallItem* wi1 = new WallItem(wall, 1, scene, m_preferences->m_outline_width,
312  m_preferences->m_mesh_magnification, m_preferences->m_mesh_offset);
313  WallItem* wi2 = new WallItem(wall, 2, scene, m_preferences->m_outline_width,
314  m_preferences->m_mesh_magnification, m_preferences->m_mesh_offset);
315  scene->addItem(wi1);
316  scene->addItem(wi2);
317  // Since the tooltip of a wall only displays the two neighboring cell indices
318  // both WallItems share the same tooltip.
319  QString wall_tt = QString("Wall %1").arg(wall->GetIndex());
320  wall_tt += QString("\nType: %1")
321  .arg(QString::fromStdString(WallType::ToString(wall->GetType())));
322  wall_tt += QString("\nCells: { %1 %2 }").arg(wall->GetC1()->GetIndex()).arg(wall->GetC2()->GetIndex());
323  wall_tt += QString("\nNodes: { %1 %2 }").arg(wall->GetN1()->GetIndex()).arg(wall->GetN2()->GetIndex());
324  wall_tt += QString("\nLength: %1").arg(wall->GetLength());
325  wall_tt += QString("\nRestLength: %1").arg(wall->GetRestLength());
326  wall_tt += QString("\nStrength: %1").arg(wall->GetStrength());
327  wi1->setToolTip(wall_tt);
328  wi2->setToolTip(wall_tt);
329  wi1->show();
330  wi2->show();
331  };
332 
333  const auto boundary_polygon_draw = [&](Cell* boundary_polygon) {
334  QPolygonF pa(boundary_polygon->GetNodes().size());
335 
336  int cc = 0;
337  for (const auto& n : boundary_polygon->GetNodes()) {
338  const auto pos = (m_preferences->m_mesh_offset + *n) * m_preferences->m_mesh_magnification;
339  pa[cc++] = QPoint(static_cast<int>(pos[0]), static_cast<int>(pos[1]));
340  }
341  auto p = scene->addPolygon(pa,
342  m_preferences->m_outline_width >= 0 ? QPen(QColor(m_preferences->m_cell_outline_color.c_str()), m_preferences->m_outline_width) : QPen(Qt::NoPen),
343  Qt::NoBrush);
344  //p->setPolygon(pa);
345  //p->setPen(m_preferences->m_outline_width >= 0 ? QPen(QColor(m_preferences->m_cell_outline_color.c_str()), m_preferences->m_outline_width) : QPen(Qt::NoPen));
346  //p->setBrush(Qt::NoBrush);
347  p->setZValue(1);
348  p->show();
349  };
350 
351  const auto mesh_draw_boundary = [&, mesh]() {
352  boundary_polygon_draw(mesh->GetBoundaryPolygon());
353  };
354 
355  // Plotting
356  if (!m_preferences->m_only_tissue_boundary && m_preferences->m_cells && m_preferences->m_tooltips) {
357  if (m_preferences->m_border_cells)
358  loop_cells(cell_draw_with_tooltip);
359  else
360  loop_nb_cells(cell_draw_with_tooltip);
361  }
362  if (!m_preferences->m_only_tissue_boundary && m_preferences->m_cells && !m_preferences->m_tooltips) {
363  if (m_preferences->m_border_cells)
364  loop_cells(cell_draw);
365  else
366  loop_nb_cells(cell_draw);
367  }
368  if (m_preferences->m_cell_centers) {
369  if (m_preferences->m_border_cells)
370  loop_cells(cell_draw_center);
371  else
372  loop_nb_cells(cell_draw_center);
373  }
374  if (m_preferences->m_fluxes) {
375  if (m_preferences->m_border_cells)
376  loop_cells(cell_draw_fluxes);
377  else
378  loop_nb_cells(cell_draw_fluxes);
379  }
380  if (m_preferences->m_cell_numbers) {
381  loop_cells(cell_draw_index);
382  }
383  if (m_preferences->m_cell_axes) {
384  loop_cells(cell_draw_axis);
385  }
386  if (m_preferences->m_cell_strain) {
387  // draw strain not implemented yet!
388  }
389  if (m_preferences->m_node_numbers) {
390  loop_nodes(node_draw_index);
391  }
392  if (m_preferences->m_walls) {
393  if(m_preferences->m_tooltips) {
394  loop_walls(wall_draw_with_tooltip);
395  } else {
396  loop_walls(wall_draw);
397  }
398  }
399  if (m_preferences->m_nodes) {
400  if (m_preferences->m_tooltips) {
401  loop_nodes(node_draw_with_tooltip);
402  } else {
403  loop_nodes(node_draw);
404  }
405  }
406  if (m_preferences->m_only_tissue_boundary) {
407  mesh_draw_boundary();
408  }
409 }
410 
411 } // namespace
Simulator interface.
STL namespace.
A cell contains walls and nodes.
Definition: Cell.h:48
Node in cell wall.
Definition: Node.h:39
Core data used during model execution.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
string ToString(Type w)
Converts a WallType::Type value to corresponding name.
Definition: WallType.cpp:49
static std::shared_ptr< ComponentFactoryProxy > Create(const string &group_name, bool throw_ok=true)
Create a factory proxy.
Interface for ArrowItem.
Namespace for SimPT shell package.
Definition: Client.cpp:50
Namespace for the core simulator.
Interface for Cell.
MeshDrawer()
Constructor.
Definition: MeshDrawer.cpp:60
void Draw(std::shared_ptr< SimPT_Sim::SimInterface > sim, QGraphicsScene *scene)
Draws the mesh to QGraphicsScene.
Definition: MeshDrawer.cpp:64
BoundaryType enumeration class.
Proxy for dealing with the factories.
Preferences for graphics viewer.
Interface for MergedPreferences.
Interface for Node.
int GetIndex() const
Return the index.
Definition: Cell.h:76
std::array< double, 3 > GetCentroid() const
Return the centroid position.
Definition: Cell.cpp:205
Interface for MeshDrawer.
Arrow composed and drawn with Qt primitives.
Definition: ArrowItem.h:31
Interface/Implementation for ReduceCellWalls.
String manipulation utilities.
Interface for NodeItem.
std::tuple< double, std::array< double, 3 >, double > GetEllipseAxes() const
Calculate axes (length and direction) area moment of inertia ellipse.
Definition: GeoData.h:50
GeoData GetGeoData() const
Return GeData (area, centroid, area moment of inertia).
Definition: Cell.cpp:225
Interface for WallItem.
Graphic wrapper for Node.
Definition: NodeItem.h:33
A cell wall, runs between cell corner points and consists of wall elements.
Definition: Wall.h:48
Interface for Wall.
WallItem shows transporter concentrations at one side of the wall.
Definition: WallItem.h:33
Interface for Mesh.