VPTissue Reference Manual
EditControlLogic.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 "EditControlLogic.h"
21 
22 #include "bio/Cell.h"
23 #include "bio/Edge.h"
24 #include "bio/Mesh.h"
25 #include "bio/Node.h"
26 #include "bio/Wall.h"
27 #include "ptree/PTreeUtils.h"
28 
29 #include <boost/iterator/iterator_facade.hpp>
30 #include <boost/optional/optional.hpp>
31 #include <boost/property_tree/detail/ptree_implementation.hpp>
32 #include <array>
33 #include <cassert>
34 #include <list>
35 #include <memory>
36 #include <QLineF>
37 #include <string>
38 #include <vector>
39 
40 namespace SimPT_Sim { class Edge; }
41 
42 namespace SimPT_Editor {
43 
44 using namespace std;
45 using namespace boost::property_tree;
46 using namespace SimPT_Sim;
47 using namespace SimPT_Sim::Util;
48 
49 EditControlLogic::EditControlLogic(unsigned int chemical_count)
50  : m_mesh(nullptr),
51  m_moving_node(false),
52  m_ptree_dirty(false)
53 {
54  m_ptree.put_child("parameters", ptree());
55  m_ptree.put_child("mesh", BuildTwoSquaresMesh(chemical_count).ToPtree());
56  m_mesh = new EditableMesh(m_ptree.get_child("mesh"));
57 }
58 
60  : m_mesh(new EditableMesh(pt.get_child("mesh"))), m_moving_node(false),
61  m_ptree_dirty(false)
62 {
63  // TODO (joeri): init m_ptree with 'pt' instead??
64  if (auto parameters = pt.get_child_optional("parameters")) {
65  m_ptree.put_child("parameters", parameters.get());
66  } else {
67  m_ptree.put_child("parameters", ptree());
68  }
69  m_ptree.put_child("mesh", m_mesh->GetMesh()->ToPtree());
70 }
71 
73 {
74  delete m_mesh;
75 }
76 
77 Mesh EditControlLogic::BuildTwoSquaresMesh(unsigned int chemical_count)
78 {
79  Mesh mesh(chemical_count);
80 
81  auto node_0 = mesh.BuildNode(0, {{ +5.0, 0.0 }}, true);
82  mesh.BuildNode(1, {{ +5.0, +10.0 }}, true);
83  mesh.BuildNode(2, {{ -5.0, +10.0 }}, true);
84  auto node_3 = mesh.BuildNode(3, {{ -5.0, 0.0 }}, true);
85  mesh.BuildNode(4, {{ -5.0, -10.0 }}, true);
86  mesh.BuildNode(5, {{ +5.0, -10.0 }}, true);
87 
88  Cell* cell_0 = mesh.BuildCell(0, {{ 0, 1, 2, 3 }});
89  Cell* cell_1 = mesh.BuildCell(1, {{ 0, 3, 4, 5 }});
90  Cell* cell_bp = mesh.BuildBoundaryPolygon({{ 0, 1, 2, 3, 4, 5}});
91 
92  Wall* wall_0 = mesh.BuildWall(0, node_3, node_0, cell_1, cell_bp);
93  Wall* wall_1 = mesh.BuildWall(1, node_0, node_3, cell_0, cell_bp);
94  Wall* wall_2 = mesh.BuildWall(2, node_3, node_0, cell_0, cell_1);
95 
96  cell_0->GetWalls().push_back(wall_1);
97  cell_0->GetWalls().push_back(wall_2);
98  cell_1->GetWalls().push_back(wall_0);
99  cell_1->GetWalls().push_back(wall_2);
100  cell_bp->GetWalls().push_back(wall_0);
101  cell_bp->GetWalls().push_back(wall_1);
102 
103  mesh.ConstructNeighborList(mesh.GetBoundaryPolygon());
104  mesh.UpdateNodeOwningNeighbors(mesh.GetBoundaryPolygon());
105  for (auto cell : mesh.GetCells()) {
106  mesh.ConstructNeighborList(cell);
107  mesh.UpdateNodeOwningNeighbors(cell);
108  }
109 
110  return mesh;
111 }
112 
114 {
115  if (!m_selected_nodes.empty()) {
116  for (Node* n : m_selected_nodes) {
117  ptree node_pt = n->NodeAttributes::ToPtree();
118  n->NodeAttributes::ReadPtree(UpdatePTree(node_pt, pt));
119  }
120  }
121  else if (!m_selected_walls.empty()) {
122  for (Wall* w : m_selected_walls) {
123  ptree wall_pt = w->WallAttributes::ToPtree();
124  w->WallAttributes::ReadPtree(UpdatePTree(wall_pt, pt));
125  }
126  }
127  else if (!m_selected_cells.empty()) {
128  for (Cell* c : m_selected_cells) {
129  ptree cell_pt = c->CellAttributes::ToPtree();
130  c->CellAttributes::ReadPtree(UpdatePTree(cell_pt, pt));
131  }
132  }
133  m_ptree_dirty = true;
134  emit Modified();
135 }
136 
137 void EditControlLogic::CopyAttributes(const ptree& pt)
138 {
139  if (!m_selected_cells.empty()) {
140  for (Cell* c : m_selected_cells) {
141  ptree new_pt = pt;
142  ptree cell_pt = c->CellAttributes::ToPtree();
143  PTreeUtils::FillPTree(new_pt, cell_pt);
144  c->CellAttributes::ReadPtree(new_pt);
145  }
146  }
147  else if (!m_selected_nodes.empty()) {
148  for (Node* n : m_selected_nodes) {
149  ptree new_pt = pt;
150  ptree node_pt = n->NodeAttributes::ToPtree();
151  PTreeUtils::FillPTree(new_pt, node_pt);
152  n->NodeAttributes::ReadPtree(new_pt);
153  }
154  }
155  else if (!m_selected_walls.empty()) {
156  for (Wall* w : m_selected_walls) {
157  ptree new_pt = pt;
158  ptree wall_pt = w->WallAttributes::ToPtree();
159  PTreeUtils::FillPTree(new_pt, wall_pt);
160  w->WallAttributes::ReadPtree(new_pt);
161  }
162  }
163  else {
164  assert(false && "No entities were selected.");
165  }
166 
167  m_ptree_dirty = true;
168  emit Modified();
169  emit SelectionChanged();
170 }
171 
172 Cell* EditControlLogic::CreateCell(Node* node1, Node* node2, const QPointF& newPoint)
173 {
174  auto newCell = m_mesh->CreateCell(node1, node2, newPoint);
175 
176  if (newCell != nullptr) {
177  SelectCells({newCell});
178  m_ptree_dirty = true;
179  emit Modified();
180  }
181 
182  return newCell;
183 }
184 
186 {
187  if (cell->HasBoundaryWall()) {
188  DeleteCells({cell});
189  return true;
190  }
191  else {
192  return false;
193  }
194 }
195 
196 void EditControlLogic::DeleteCells(const list<Cell*>& cells)
197 {
198  m_mesh->DeleteCells(cells);
199  Deselect();
200  m_ptree_dirty = true;
201  emit Modified();
202 }
203 
205 {
206  if (m_mesh->DeleteTwoDegreeNode(node)) {
207  Deselect();
208  m_ptree_dirty = true;
209  emit Modified();
210  return true;
211  }
212  else {
213  return false;
214  }
215 }
216 
218 {
219  m_selected_nodes.clear();
220  m_selected_walls.clear();
221  m_selected_cells.clear();
222  emit SelectionChanged();
223  emit StatusInfoChanged("No items selected.");
224 }
225 
226 const ptree& EditControlLogic::GetParameters() const
227 {
228  return m_ptree.get_child("parameters");
229 }
230 
231 bool EditControlLogic::MoveNode(Node* node, double x, double y)
232 {
233  if (m_mesh->DisplaceNode(node, x, y)) {
234  m_ptree_dirty = true;
235  m_moving_node = true;
236  emit Moved(node, x, y);
237  return true;
238  }
239  else {
240  return false;
241  }
242 }
243 
245 {
246  if (m_ptree_dirty) {
247  m_ptree.put_child("mesh", m_mesh->GetMesh()->ToPtree());
248  }
249 
250  return m_ptree;
251 }
252 
253 void EditControlLogic::ReplaceCell(Cell* cell, list<QPolygonF> newCells)
254 {
255  m_mesh->ReplaceCell(cell, newCells);
256  Deselect();
257  m_ptree_dirty = true;
258  emit Modified();
259 }
260 
261 void EditControlLogic::SelectCells(const std::list<Cell*>& cells)
262 {
263  m_selected_cells = cells;
264  // Gives better info for the StatusInfoChanged signal.
265  m_selected_cells.sort([](Cell* c1, Cell* c2){return c1->GetIndex() < c2->GetIndex();});
266  emit SelectionChanged();
267 
268  std::string info = "Cells selected: "
269  + to_string(m_selected_cells.front()->GetIndex());
270  for (auto it = next(m_selected_cells.begin()); it != m_selected_cells.end(); it++) {
271  info += ", " + to_string((*it)->GetIndex());
272  }
273  emit StatusInfoChanged(info);
274 }
275 
276 void EditControlLogic::SelectEdges(const std::list<Edge>& edges)
277 {
278  m_selected_walls.clear();
279  for (const Edge& edge : edges) {
280  Wall* w = m_mesh->GetMesh()->FindWall(edge);
281  if (w != nullptr
282  && std::find(m_selected_walls.begin(), m_selected_walls.end(), w) == m_selected_walls.end()) {
283  m_selected_walls.push_back(w);
284  }
285  }
286  // Gives better info for the StatusInfoChanged signal.
287  m_selected_walls.sort([](Wall* w1, Wall* w2){return w1->GetIndex() < w2->GetIndex();});
288  emit SelectionChanged();
289 
290  std::string info = "Walls selected: "
291  + to_string(m_selected_walls.front()->GetIndex());
292  for (auto it = next(m_selected_walls.begin()); it != m_selected_walls.end(); it++) {
293  info += ", " + to_string((*it)->GetIndex());
294  }
295  emit StatusInfoChanged(info);
296 }
297 
298 void EditControlLogic::SelectNodes(const std::list<Node*>& nodes)
299 {
300  assert(nodes.size() > 0 && "No nodes were selected.");
301 
302  m_selected_nodes = nodes;
303  // Gives better info for the StatusInfoChanged signal.
304  m_selected_nodes.sort([](Node* n1, Node* n2){return n1->GetIndex() < n2->GetIndex();});
305  emit SelectionChanged();
306 
307  string info = "Nodes selected: "
308  + to_string(m_selected_nodes.front()->GetIndex());
309  for (auto it = next(m_selected_nodes.begin()); it != m_selected_nodes.end(); it++) {
310  info += ", " + to_string((*it)->GetIndex());
311  }
312  emit StatusInfoChanged(info);
313 }
314 
315 void EditControlLogic::SetParameters(const boost::property_tree::ptree& pt)
316 {
317  m_ptree.put_child("parameters", pt);
318  emit Modified();
319 }
320 
321 vector<Cell*> EditControlLogic::SplitCell(Node* node1, Node* node2)
322 {
323  vector<Cell*> cells = m_mesh->SplitCell(node1, node2);
324 
325  if (cells.size() > 1) {
326  m_ptree_dirty = true;
327 
328  emit Modified();
329  }
330 
331  return cells;
332 }
333 
334 vector<Cell*> EditControlLogic::SplitCell(Cell* cell,
335  Node* node1, Node* node2, bool modified)
336 {
337  vector<Cell*> cells = m_mesh->SplitCell(cell, node1, node2);
338 
339  if (cells.size() > 1) {
340  m_ptree_dirty = true;
341 
342  if (modified) {
343  emit Modified();
344  }
345  }
346 
347  return cells;
348 }
349 
351 {
352  m_ptree_dirty = true;
353  emit Modified();
354  return m_mesh->SplitEdge(edge);
355 }
356 
358 {
359  if (m_moving_node) {
360  m_moving_node = false;
361  emit Modified();
362  emit StoppedMoving();
363  }
364 }
365 
366 ptree EditControlLogic::UpdatePTree(ptree pt1, ptree pt2)
367 {
368  assert(pt1.data() != "?" && "The data of the first ptree should be known completely.");
369 
370  ptree pt;
371  if (pt1.data() != pt2.data()) {
372  pt = ptree(pt2.data());
373  }
374  else {
375  pt = ptree(pt1.data());
376  }
377 
378  if (pt1.size() == 0) {
379  return pt;
380  }
381  else {
382  ptree::const_iterator it1 = pt1.begin();
383  ptree::const_iterator it2 = pt2.begin();
384  while (it1 != pt1.end() && it2 != pt2.end()) {
385  if (it1->first == it2->first) {
386  if (it2->second.data() != "?") {
387  pt.add_child(it1->first, UpdatePTree(it1->second, it2->second));
388  ++it1;
389  ++it2;
390  }
391  else if (pt1.count(it1->first) < pt2.count(it2->first)) {
392  it2++;
393  }
394  else {
395  pt.add_child(it1->first, it1->second);
396  ++it1;
397  ++it2;
398  }
399  }
400  else if (it1->first < it2->first) {
401  if (it1->second.data() != "?") {
402  pt.add_child(it1->first, it1->second);
403  }
404  ++it1;
405  }
406  else { //it1->first > it2->first
407  if (it2->second.data() != "?") {
408  pt.add_child(it2->first, it2->second);
409  }
410  ++it2;
411  }
412  }
413 
414  for (ptree::const_iterator it = it1; it != pt1.end(); ++it) {
415  if (it1->second.data() != "?") {
416  pt.add_child(it->first, it->second);
417  }
418  }
419  for (ptree::const_iterator it = it2; it != pt2.end(); ++it) {
420  if (it2->second.data() != "?") {
421  pt.add_child(it->first, it->second);
422  }
423  }
424 
425  return pt;
426  }
427 }
428 
429 } // namespace
void StopMoveNode()
Stop moving a node after moving it.
void SetParameters(const boost::property_tree::ptree &)
Set parameters ptree.
STL namespace.
A cell contains walls and nodes.
Definition: Cell.h:48
Namespace for SimPT tissue editor package.
Definition: Cell.h:32
Node in cell wall.
Definition: Node.h:39
bool MoveNode(Node *node, double x, double y)
See EditableMesh::DisplaceCell for more information.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
void DeleteCells(const std::list< Cell * > &cells)
Delete the given cells in the mesh.
static void FillPTree(boost::property_tree::ptree &pt1, const boost::property_tree::ptree &pt2)
Fill the first ptree with the second ptree.
Definition: PTreeUtils.cpp:111
const std::list< Wall * > & GetWalls() const
Access the cell's walls.
Definition: Cell.h:88
virtual ~EditControlLogic()
Destructor.
Cell * CreateCell(Node *node1, Node *node2, const QPointF &newPoint)
Creates a new cell with the two given nodes and a third new point.
PTreeUtils interface.
Namespace for the core simulator.
bool DeleteTwoDegreeNode(Node *node)
Deletes the given node from the mesh (which should stay consistent).
An Edge connects two nodes and is ambidextrous.
Definition: Edge.h:31
const boost::property_tree::ptree & ToPTree()
Get the PTree associated with the mesh.
Interface for Cell.
void CopyAttributes(const boost::property_tree::ptree &pt)
Copy the given attributes to the selected cells.
void StatusInfoChanged(const std::string &info)
Emitted when certain info about the logic has changed.
void Modified()
Emitted when data has been modified.
std::shared_ptr< SimPT_Sim::Mesh > & GetMesh()
Get the mesh.
void SelectEdges(const std::list< Edge > &edges)
Select the given edges.
void DeleteCells(const std::list< Cell * > &cells)
Deletes the given cell from the mesh.
Node * SplitEdge(const Edge &edge)
Split a given edge at the center.
void ChangeAttributes(const boost::property_tree::ptree &pt)
Change the attributes of the selected items to the attributes in the given ptree. ...
std::vector< Cell * > SplitCell(Cell *cell, Node *node1, Node *node2, bool modified=false)
See EditableMesh::SplitCell for more information.
void SelectNodes(const std::list< Node * > &nodes)
Select the given nodes.
void SelectCells(const std::list< Cell * > &cells)
Select the given cells.
void StoppedMoving()
Emitted when data has been modified.
std::vector< Cell * > SplitCell(Node *node1, Node *node2)
Does the same as SplitCell, but finds the correct cell that should be split.
Interface for Node.
void Moved(Node *node, double x, double y)
Emitted when the given node has been moved to the given coordinates.
void Deselect()
Deselect the selected items.
int GetIndex() const
Return the index.
Definition: Cell.h:76
bool DeleteCell(Cell *cell)
Delete the given cell in the mesh.
Interface for Edge.
bool DisplaceNode(Node *node, double x, double y)
Place a node at the given coordinates.
Cell * CreateCell(Node *node1, Node *node2, const QPointF &newPoint)
See EditableMesh::CreateCell for more information.
Structure of cells; key data structure.
Definition: Mesh.h:62
void ReplaceCell(Cell *cell, std::list< QPolygonF > newCells)
See EditableMesh::ReplaceCell for more information.
CircularIterator< T > next(CircularIterator< T > i)
Helper yields the position the iterator would have if moved forward (in circular fashion) by 1 positi...
EditControlLogic(unsigned int chemical_count)
Constructs a default tissue, which is an upward triangle.
An editable mesh with actions to alter the construction of the mesh.
Definition: EditableMesh.h:35
Node * SplitEdge(const Edge &edge)
Split a given edge at the center.
Interface for LeafControlLogic.
A cell wall, runs between cell corner points and consists of wall elements.
Definition: Wall.h:48
void SelectionChanged()
Emitted when selection has changed.
bool DeleteNode(Node *node)
Delete the given node in the mesh.
Interface for Wall.
void ReplaceCell(Cell *cell, std::list< QPolygonF > newCells)
Replace a given cell with a set of new cells.
Interface for Mesh.