47 : m_mesh(
PBMBuilder().Build(pt)), m_cells(m_mesh->GetCells()),
48 m_nodes(m_mesh->GetNodes()), m_walls(m_mesh->GetWalls()) {}
55 for (
auto nb : m_mesh->GetNodeOwningNeighbors(node1)) {
56 if (nb.GetCell()->GetIndex() != -1) {
57 owners.push_back(nb.GetCell());
60 for (
auto nb : m_mesh->GetNodeOwningNeighbors(node2)) {
61 if (nb.GetCell()->GetIndex() != -1) {
62 owners.push_back(nb.GetCell());
65 owners.sort([](
Cell* c1,
Cell* c2) {
return c1 < c2;});
71 list<Cell*> commonOwners;
72 auto owner = adjacent_find(owners.begin(), owners.end(), eql);
73 while (owner != owners.end()) {
74 commonOwners.push_back(*owner);
75 owner = adjacent_find(++owner, owners.end(), eql);
78 if (commonOwners.empty()) {
81 else if (cell !=
nullptr) {
82 if (find(commonOwners.begin(), commonOwners.end(), cell) != commonOwners.end()) {
84 commonOwners.push_back(cell);
91 QLineF cut((*node1)[0], (*node1)[1], (*node2)[0], (*node2)[1]);
92 for (
Cell* c : commonOwners) {
94 for (
Node* n : c->GetNodes()) {
95 polygon.push_back(QPointF((*n)[0], (*n)[1]));
99 if (polygons.size() == 2) {
101 auto it = polygons.begin();
102 while (it != polygons.end() && ok) {
103 if (!it->contains(cut.p1()) || !it->contains(cut.p2())) {
106 for (
const QPointF& p : *it) {
107 if (!polygon.contains(p)) {
124 assert(node1->IsAtBoundary() && node2->IsAtBoundary()
125 &&
"The two given nodes aren't located at the boundary of the mesh.");
126 assert(find(m_mesh->GetBoundaryPolygon()->GetNodes().begin(), m_mesh->GetBoundaryPolygon()->GetNodes().end(), node1) != m_mesh->GetBoundaryPolygon()->GetNodes().end()
127 && find(m_mesh->GetBoundaryPolygon()->GetNodes().begin(), m_mesh->GetBoundaryPolygon()->GetNodes().end(), node1) != m_mesh->GetBoundaryPolygon()->GetNodes().end()
128 &&
"The two given nodes aren't located at the boundary of the mesh.");
130 QPolygonF boundaryPoints;
131 for (
Node* n : m_mesh->GetBoundaryPolygon()->GetNodes()) {
132 boundaryPoints.append(QPointF((*n)[0], (*n)[1]));
135 list<QLineF> excluded;
136 list<QLineF> included({QLineF(QPointF((*node1)[0], (*node1)[1]), newPoint), QLineF(QPointF((*node2)[0], (*node2)[1]), newPoint)});
137 if (boundaryPoints.contains(newPoint) || boundaryPoints.containsPoint(newPoint, Qt::OddEvenFill)
138 || !IsConsistent(excluded, included)) {
145 list<QPolygonF> polygons({QPolygonF(), QPolygonF()});
146 auto current = polygons.begin();
148 QPointF point1((*node1)[0], (*node1)[1]);
149 QPointF point2((*node2)[0], (*node2)[1]);
151 for (
const QPointF& p : boundaryPoints) {
153 if (p == point1 || p == point2) {
154 current->append(newPoint);
155 if (++current == polygons.end()) {
156 current = polygons.begin();
163 QPolygonF polygon = polygons.front().intersected(polygons.back());
164 if (polygon.front() == polygon.back()) {
170 reverse(polygon.begin(), polygon.end());
175 rotate(polygon.begin(), find(polygon.begin(), polygon.end(), newPoint), polygon.end());
176 if (*
next(polygon.begin()) == point1) {
178 swap(point1, point2);
181 assert(*
next(polygon.begin()) == point2
182 &&
"One of the two points should be next to the new point.");
186 auto newNode = m_mesh->BuildNode({{newPoint.x(), newPoint.y(), 0}},
true);
189 auto oldBoundaryNodes = m_mesh->GetBoundaryPolygon()->GetNodes();
190 auto node_it = find(oldBoundaryNodes.begin(), oldBoundaryNodes.end(), node1);
191 rotate(oldBoundaryNodes.begin(), node_it, oldBoundaryNodes.end());
194 auto& newBoundaryNodes = m_mesh->GetBoundaryPolygon()->GetNodes();
195 node_it = find(newBoundaryNodes.begin(), newBoundaryNodes.end(), node2);
196 rotate(newBoundaryNodes.begin(), node_it, newBoundaryNodes.end());
197 node_it = find(newBoundaryNodes.begin(), newBoundaryNodes.end(), node1);
198 newBoundaryNodes.erase(
next(node_it), newBoundaryNodes.end());
199 newBoundaryNodes.push_back(newNode);
200 node_it = find(newBoundaryNodes.begin(), newBoundaryNodes.end(), node1);
201 rotate(newBoundaryNodes.begin(), node_it, newBoundaryNodes.end());
202 m_mesh->GetBoundaryPolygon()->SetGeoDirty();
205 if (m_walls.size() == 0) {
206 assert(m_cells.size() == 1 &&
"There should be two cells in the mesh.");
208 Cell* cell = m_cells.front();
210 Wall* newWall = m_mesh->BuildWall(node2, node1, cell, m_mesh->GetBoundaryPolygon());
211 newWall->GetC1()->AddWall(newWall);
212 newWall->GetC2()->AddWall(newWall);
213 m_mesh->UpdateNodeOwningWalls(newWall);
215 newWall = m_mesh->BuildWall(node1, node2, cell, m_mesh->GetBoundaryPolygon());
216 newWall->GetC1()->AddWall(newWall);
217 newWall->GetC2()->AddWall(newWall);
218 m_mesh->UpdateNodeOwningWalls(newWall);
222 assert(m_walls.size() >= 2 &&
"There can't be one wall in the mesh.");
224 auto& boundaryWalls = m_mesh->GetBoundaryPolygon()->GetWalls();
226 if (m_mesh->GetNodeOwningNeighbors(node1).size() == 2) {
227 auto endpoint = oldBoundaryNodes.rbegin();
228 while (m_mesh->GetNodeOwningNeighbors(*endpoint).size() == 2) {
230 assert(endpoint != oldBoundaryNodes.rend()
231 &&
"There should be at least two endpoints with more than 2 owners in the mesh.");
234 auto wall = find_if(boundaryWalls.begin(), boundaryWalls.end(), [endpoint](
Wall* w){
return w->GetN1() == *endpoint;});
235 assert(wall != boundaryWalls.end() &&
"There should be a wall for this endpoint.");
237 Wall* newWall = m_mesh->BuildWall(node1, (*wall)->GetN2(), (*wall)->GetC1(), (*wall)->GetC2());
238 newWall->WallAttributes::operator=(**wall);
239 newWall->GetC1()->AddWall(newWall);
240 newWall->GetC2()->AddWall(newWall);
242 (*wall)->SetN2(node1);
243 (*wall)->SetLengthDirty();
245 m_mesh->UpdateNodeOwningWalls(newWall);
248 if (m_mesh->GetNodeOwningNeighbors(node2).size() == 2) {
249 auto endpoint = find(oldBoundaryNodes.begin(), oldBoundaryNodes.end(), node2);
250 while (m_mesh->GetNodeOwningNeighbors(*endpoint).size() == 2) {
252 assert(endpoint != oldBoundaryNodes.end() &&
"There should be at least two endpoints with more than 2 owners in the mesh.");
255 auto wall = find_if(boundaryWalls.begin(), boundaryWalls.end(), [endpoint](
Wall* w){
return w->GetN2() == *endpoint;});
256 assert(wall != boundaryWalls.end() &&
"There should be a wall for this endpoint.");
258 Wall* newWall = m_mesh->BuildWall((*wall)->GetN1(), node2, (*wall)->GetC1(), (*wall)->GetC2());
259 newWall->WallAttributes::operator=(**wall);
260 newWall->GetC1()->AddWall(newWall);
261 newWall->GetC2()->AddWall(newWall);
263 (*wall)->SetN1(node2);
264 (*wall)->SetLengthDirty();
266 m_mesh->UpdateNodeOwningWalls(newWall);
271 list<Node*> cellNodes(oldBoundaryNodes.begin(),
next(find(oldBoundaryNodes.begin(), oldBoundaryNodes.end(), node2)));
273 cellNodes.push_front(newNode);
275 vector<unsigned int> nodeIDs(cellNodes.size());
276 transform(cellNodes.begin(), cellNodes.end(), nodeIDs.begin(), [](
Node* n){
return n->GetIndex();});
279 auto newCell = m_mesh->BuildCell(nodeIDs);
282 const auto boundaryWalls = m_mesh->GetBoundaryPolygon()->GetWalls();
283 for (
Wall* w : boundaryWalls) {
284 auto n1 = find(cellNodes.begin(), cellNodes.end(), w->GetN1());
285 auto n2 = find(cellNodes.begin(), cellNodes.end(), w->GetN2());
286 if (n1 != cellNodes.end() && n2 != cellNodes.end() && (*n2 != node1 || *n1 != node2)) {
288 m_mesh->GetBoundaryPolygon()->ReassignWall(w, newCell);
293 Wall* newWall = m_mesh->BuildWall(node1, node2,
294 newCell, m_mesh->GetBoundaryPolygon());
295 newWall->GetC1()->AddWall(newWall);
296 newWall->GetC2()->AddWall(newWall);
297 m_mesh->UpdateNodeOwningWalls(newWall);
300 for (
Node* n : newCell->GetNodes()) {
302 auto& owners = m_mesh->GetNodeOwningNeighbors(n);
303 auto owner = find_if(owners.begin(), owners.end(),
304 [](
const NeighborNodes& nb){
return nb.GetCell()->GetIndex() == -1;});
305 assert(owner != owners.end()
306 &&
"Node without a boundary neighbor in new cell that wasn't new node.");
313 m_mesh->GetNodeOwningNeighbors(*boundary_cit).push_back(
315 *
prev(boundary_cit), *
next(boundary_cit)));
316 }
while (*boundary_cit++ != node2);
319 m_mesh->ConstructNeighborList(newCell);
320 for (
Cell* c : m_mesh->GetNeighbors(newCell)) {
321 m_mesh->ConstructNeighborList(c);
323 m_mesh->ConstructNeighborList(m_mesh->GetBoundaryPolygon());
326 for (
Node* n : newCell->GetNodes()) {
337 assert(cells.size() < m_cells.size() &&
"Can't delete all cells in the mesh.");
338 assert(find_if(cells.begin(), cells.end(), [
this](
Cell* c) {
return (find(m_cells.begin(), m_cells.end(), c) == m_cells.end());}) == cells.end()
339 &&
"There's a given cell that doesn't exist in the mesh.");
346 auto cell = m_cells.begin();
347 while (cell != m_cells.end()) {
348 if (find(cells.begin(), cells.end(), *cell) != cells.end()) {
349 for (
Node* n : (*cell)->GetNodes()) {
350 n->SetAtBoundary(
true);
353 for (
Wall* w : (*cell)->GetWalls()) {
354 if (w->IsAtBoundary()) {
357 m_walls.erase(remove_if(m_walls.begin(), m_walls.end(),
358 [w](
Wall* wall){
return wall == w;}),
362 else if (w->GetC1() == *cell) {
363 w->SetC1(w->GetC2());
364 w->SetC2(m_mesh->GetBoundaryPolygon());
366 Node* tmpNode = w->GetN1();
367 w->SetN1(w->GetN2());
374 w->SetC2(m_mesh->GetBoundaryPolygon());
378 m_mesh->GetCells().erase(cell);
386 if (m_cells.size() == 1) {
388 m_cells.front()->GetWalls().clear();
389 m_mesh->GetBoundaryPolygon()->GetWalls().clear();
392 for (
auto n : m_nodes) {
393 m_mesh->GetNodeOwningNeighbors(n).clear();
396 list<Node*> nodesToKeep;
397 for (
auto c : m_cells) {
400 nodesToKeep.push_back(*cit);
401 m_mesh->GetNodeOwningNeighbors(*cit).push_back(
403 }
while (++cit != c->GetNodes().begin());
407 list<Node*> boundaryNodes;
408 auto node = m_nodes.begin();
409 while (node != m_nodes.end()) {
410 if (find(nodesToKeep.begin(), nodesToKeep.end(), *node) == nodesToKeep.end()) {
411 m_mesh->RemoveNodeFromOwnerLists(*node);
415 if ((*node)->IsAtBoundary()) {
416 boundaryNodes.push_back(*node);
423 Node* current = boundaryNodes.front();
424 boundaryNodes.pop_front();
425 m_mesh->GetBoundaryPolygon()->GetNodes().clear();
426 m_mesh->GetBoundaryPolygon()->GetNodes().push_back(current);
427 while (!boundaryNodes.empty()) {
430 list<Node*> firstNeighbors;
433 list<Node*> secondNeighbors;
434 for (
NeighborNodes nb : m_mesh->GetNodeOwningNeighbors(current)) {
435 if (nb.GetNb1()->IsAtBoundary()) {
436 firstNeighbors.push_back(nb.GetNb1());
438 if (nb.GetNb2()->IsAtBoundary()) {
439 secondNeighbors.push_back(nb.GetNb2());
443 auto next = find_if(boundaryNodes.begin(), boundaryNodes.end(),
444 [firstNeighbors, secondNeighbors](
Node* n) {
445 return find(firstNeighbors.begin(), firstNeighbors.end(), n)
446 == firstNeighbors.end()
447 && find(secondNeighbors.begin(), secondNeighbors.end(), n)
448 != secondNeighbors.end();
450 assert(
next != boundaryNodes.end()
451 &&
"Inconsistency: No boundary neighbor to current boundary node.");
454 boundaryNodes.erase(
next);
455 m_mesh->GetBoundaryPolygon()->GetNodes().push_back(current);
459 m_mesh->GetBoundaryPolygon()->GetNodes().begin());
461 m_mesh->GetNodeOwningNeighbors(*cit).push_back(
463 }
while (++cit != m_mesh->GetBoundaryPolygon()->GetNodes().begin());
466 auto cmp_boundary_walls = [](
Wall* w1,
Wall* w2) {
467 Cell* c1 = w1->GetC1()->
GetIndex() != -1 ? w1->GetC1() : w1->GetC2();
468 Cell* c2 = w2->GetC1()->
GetIndex() != -1 ? w2->GetC1() : w2->GetC2();
471 auto eql_boundary_walls = [](
Wall* w1,
Wall* w2) {
472 Cell* c1 = w1->GetC1()->
GetIndex() != -1 ? w1->GetC1() : w1->GetC2();
473 Cell* c2 = w2->GetC1()->
GetIndex() != -1 ? w2->GetC1() : w2->GetC2();
477 list<Wall*> boundaryWalls;
478 for (
auto w : m_walls) {
479 if (w->IsAtBoundary()) {
480 boundaryWalls.push_back(w);
485 m_mesh->GetBoundaryPolygon()->GetWalls().clear();
486 boundaryWalls.sort(cmp_boundary_walls);
487 auto wall = adjacent_find(boundaryWalls.begin(), boundaryWalls.end(), eql_boundary_walls);
488 while (wall != boundaryWalls.end()) {
491 while (
next != boundaryWalls.end() && eql_boundary_walls(*wall, *
next)) {
493 if ((*wall)->GetN1() == (*next)->GetN1()) {
494 (*wall)->SetN1((*next)->GetN2());
496 else if ((*wall)->GetN1() == (*next)->GetN2()) {
497 (*wall)->SetN1((*next)->GetN1());
499 else if ((*wall)->GetN2() == (*next)->GetN1()) {
500 (*wall)->SetN2((*next)->GetN2());
502 else if ((*wall)->GetN2() == (*next)->GetN2()) {
503 (*wall)->SetN2((*next)->GetN1());
510 (*wall)->SetLengthDirty();
512 (*next)->GetC1()->GetWalls().remove(*
next);
513 (*next)->GetC2()->GetWalls().remove(*
next);
516 boundaryWalls.erase(
next);
519 tmpWall->SetN1(
nullptr);
520 tmpWall->SetN2(
nullptr);
521 m_mesh->UpdateNodeOwningWalls(*wall);
524 m_walls.erase(remove_if(
525 m_walls.begin(), m_walls.end(),
526 [tmpWall](
Wall* w){
return w == tmpWall;}),
532 wall = adjacent_find(++wall, boundaryWalls.end(), eql_boundary_walls);
535 for (
auto w : boundaryWalls) {
536 m_mesh->GetBoundaryPolygon()->GetWalls().push_back(w);
539 m_mesh->GetBoundaryPolygon()->SetGeoDirty();
541 m_mesh->ConstructNeighborList(m_mesh->GetBoundaryPolygon());
543 for (
auto c : m_mesh->GetCells()) {
544 m_mesh->ConstructNeighborList(c);
552 if (m_mesh->GetWalls().size() == 0) {
553 for (
auto n : m_mesh->GetNodes()) {
554 m_mesh->GetNodeOwningWalls(n).clear();
558 for (
auto w : m_mesh->GetWalls()) {
559 m_mesh->UpdateNodeOwningWalls(w);
567 list<QLineF> oldEdges;
568 list<QLineF> newEdges;
569 for (
NeighborNodes neighbor : m_mesh->GetNodeOwningNeighbors(node)) {
570 QLineF oldEdge1((*neighbor.GetNb1())[0], (*neighbor.GetNb1())[1], (*node)[0], (*node)[1]);
571 QLineF oldEdge2((*neighbor.GetNb2())[0], (*neighbor.GetNb2())[1], (*node)[0], (*node)[1]);
572 QLineF newEdge((*neighbor.GetNb1())[0], (*neighbor.GetNb1())[1], (*neighbor.GetNb2())[0], (*neighbor.GetNb2())[1]);
574 if (find(oldEdges.begin(), oldEdges.end(), oldEdge1) == oldEdges.end()) {
575 oldEdges.push_front(oldEdge1);
577 if (find(oldEdges.begin(), oldEdges.end(), oldEdge2) == oldEdges.end()) {
578 oldEdges.push_front(oldEdge2);
580 if (find(newEdges.begin(), newEdges.end(), newEdge) == newEdges.end()) {
581 newEdges.push_front(newEdge);
586 DeleteTwoDegreeNodeInconsistent(node);
598 bool EditableMesh::DeleteTwoDegreeNodeInconsistent(
Node* node)
601 list<NeighborNodes> neighbors = m_mesh->GetNodeOwningNeighbors(node);
603 if (neighbors.size() != 2) {
607 auto nodeOwningWalls = m_mesh->GetNodeOwningWalls(node);
608 if (nodeOwningWalls.size() == 1) {
609 nodeOwningWalls.front()->SetLengthDirty();
612 assert(nodeOwningWalls.size() == 0 && m_walls.size() == 0
613 &&
"A two degree node with no wall owners is only possible for one cell in the mesh (no walls).");
616 Node* n1 = neighbors.front().GetNb1();
617 Node* n2 = neighbors.front().GetNb2();
628 return (nb.GetNb1() == node || nb.GetNb2() == node);
633 list<NeighborNodes>& owners = m_mesh->GetNodeOwningNeighbors(n1);
634 auto owner = find_if(owners.begin(), owners.end(), is_nb);
635 while (owner != owners.end()) {
636 if (owner->GetNb1() == node) {
637 const NeighborNodes tmp(owner->GetCell(), n2, owner->GetNb2());
640 else if (owner->GetNb2() == node) {
641 const NeighborNodes tmp(owner->GetCell(), owner->GetNb1(), n2);
644 owner = find_if(owner, owners.end(), is_nb);
650 list<NeighborNodes>& owners = m_mesh->GetNodeOwningNeighbors(n2);
651 auto owner = find_if(owners.begin(), owners.end(), is_nb);
652 while (owner != owners.end()) {
653 if (owner->GetNb1() == node) {
654 const NeighborNodes tmp(owner->GetCell(), n1, owner->GetNb2());
657 else if (owner->GetNb2() == node) {
658 const NeighborNodes tmp(owner->GetCell(), owner->GetNb1(), n1);
661 owner = find_if(owner, owners.end(), is_nb);
665 m_mesh->RemoveNodeFromOwnerLists(node);
666 auto it = m_nodes.begin();
667 while (it != m_nodes.end()) {
680 double old_x = (*node)[0];
681 double old_y = (*node)[1];
685 if (IsConsistent(node)) {
686 for (
const auto &nb : m_mesh->GetNodeOwningNeighbors(node)) {
687 nb.GetCell()->SetGeoDirty();
689 for (
const auto &wall : m_mesh->GetNodeOwningWalls(node)) {
690 wall->SetLengthDirty();
702 void EditableMesh::FixCellIDs()
705 return c1->
GetIndex() < c2->GetIndex();
708 sort(m_cells.begin(), m_cells.end(), cmp);
709 for (
unsigned int i = 0; i < m_cells.size(); i++) {
710 m_cells[i]->m_index = i;
713 m_mesh->m_cell_next_id = m_cells.size();
716 void EditableMesh::FixNodeIDs()
719 return n1->GetIndex() < n2->GetIndex();
722 sort(m_nodes.begin(), m_nodes.end(), cmp);
723 for (
unsigned int i = 0; i < m_nodes.size(); i++) {
724 m_nodes[i]->m_index = i;
727 m_mesh->m_node_next_id = m_nodes.size();
730 void EditableMesh::FixWallIDs()
733 return w1->GetIndex() < w2->GetIndex();
736 sort(m_walls.begin(), m_walls.end(),cmp);
737 for (
unsigned int i = 0; i < m_walls.size(); i++) {
738 m_walls[i]->m_wall_index = i;
741 m_mesh->m_wall_next_id = m_walls.size();
749 bool EditableMesh::IsConsistent(
const list<QLineF>& excluded,
const list<QLineF>& included)
const
752 auto is_excluded = [excluded](
const QLineF& edge) {
753 return (find(excluded.begin(), excluded.end(), edge) != excluded.end());
757 auto is_included = [included](
const QLineF& edge) {
758 return (find(included.begin(), included.end(), edge) != included.end());
763 for (
Cell* cell : m_cells) {
766 QLineF newEdge((**cit)[0], (**cit)[1], (**
next(cit))[0], (**
next(cit))[1]);
767 if (!is_excluded(newEdge) && !is_included(newEdge)
768 && find(edges.begin(), edges.end(), newEdge) == edges.end()) {
769 edges.push_back(newEdge);
771 }
while (++cit != cell->GetNodes().begin());
776 for (QLineF e1 : edges) {
777 for (QLineF e2 : included) {
778 QLineF::IntersectType intersection = e1.intersect(e2,
nullptr);
779 if (intersection == QLineF::BoundedIntersection
780 && e1.p1() != e2.p1() && e1.p1() != e2.p2()
781 && e1.p2() != e2.p1() && e1.p2() != e2.p2()) {
791 bool EditableMesh::IsConsistent(
Node* node)
const
793 list<Cell*> neighbors;
794 for (
const NeighborNodes& nb : m_mesh->GetNodeOwningNeighbors(node)) {
795 if (nb.GetCell()->GetIndex() != -1 && find(neighbors.begin(), neighbors.end(), nb.GetCell()) == neighbors.end()) {
796 neighbors.push_back(nb.GetCell());
800 if (node->IsAtBoundary()) {
801 for (
Node* n : m_mesh->GetBoundaryPolygon()->GetNodes()) {
802 for (
const NeighborNodes& nb : m_mesh->GetNodeOwningNeighbors(n)) {
803 if (nb.GetCell()->GetIndex() != -1 && find(neighbors.begin(), neighbors.end(), nb.GetCell()) == neighbors.end()) {
804 neighbors.push_back(nb.GetCell());
810 list<QPolygonF> polygons;
811 for (
Cell* c : neighbors) {
813 for (
Node* n : c->GetNodes()) {
814 polygon.append(QPointF((*n)[0], (*n)[1]));
816 polygons.push_back(polygon);
819 for (
auto p1 = polygons.begin(); p1 != polygons.end(); p1++) {
824 for (
auto p2 =
next(p1); p2 != polygons.end(); p2++) {
825 if (p1->intersected(*p2).size() >= 3) {
836 if (!cell->HasBoundaryWall() || m_cells.size() <= 1
837 || find_if(m_cells.begin(), m_cells.end(), [cell](
Cell* c){
return c == cell;}) == m_cells.end()) {
843 if (wall->IsAtBoundary()) {
846 auto firstNode = (wall->GetC1() == cell ? wall->GetN2() : wall->GetN1());
847 rotate(nodes.begin(),
next(find(nodes.begin(), nodes.end(), firstNode)), nodes.end());
848 auto secondNode = (wall->GetC1() == cell ? wall->GetN1() : wall->GetN2());
850 for (
auto it = nodes.begin(); it != find(nodes.begin(), nodes.end(), secondNode); it++) {
851 if ((*it)->IsAtBoundary()) {
860 assert(
false &&
"There's no boundary wall, while this already has been verified.");
867 const list<NeighborNodes> neighbors = m_mesh->GetNodeOwningNeighbors(node);
868 if (neighbors.size() != 2) {
878 &&
"Inconsistency in the neighbor list of the given node.");
889 assert(find_if(newCells.begin(), newCells.end(),
890 [](
const QPolygonF& p){
return p.isClosed();}) == newCells.end()
891 &&
"All the given polygons should be open.");
892 assert(find_if(newCells.begin(), newCells.end(),
893 [](
const QPolygonF& p){
return p.size() < 3;}) == newCells.end()
894 &&
"There's a given polygon which is invalid. (less than three corners)");
895 assert(!newCells.empty() &&
"There are no new cells given.");
896 assert(all_of(newCells.begin(), newCells.end(),
898 &&
"The given polygons weren't counter-clockwise.");
900 for (
const QPolygonF& p : newCells) {
901 if (p.contains(QPointF((*n)[0], (*n)[1]))) {
906 }) &&
"Not all the points of the cell were present in the new cells.");
908 if (newCells.size() == 1) {
914 auto cmp_points = [](
const QPointF& p1,
const QPointF& p2) {
915 return p1 != p2 && (p1.x() < p2.x() || (p1.x() == p2.x() && p1.y() < p2.y()));
919 auto cmp_edges = [](
const Edge& e1,
const Edge& e2) {
920 return e1.
GetFirst()->GetIndex() < e2.GetFirst()->GetIndex()
921 || (e1.
GetFirst()->GetIndex() == e2.GetFirst()->GetIndex()
922 && e1.
GetSecond()->GetIndex() < e2.GetSecond()->GetIndex());
926 auto is_perturbed = [](
const QPointF& p1,
const QPointF& p2) {
927 return fabs(p1.x() - p2.x()) < g_accuracy && fabs(p1.y() - p2.y()) < g_accuracy;
931 auto perturb_line = [](QLineF line) {
932 line.setLength(line.length() + g_accuracy);
933 line.setPoints(line.p2(), line.p1());
934 line.setLength(line.length() + g_accuracy);
935 line.setPoints(line.p2(), line.p1());
941 map<QPointF, Node*, decltype(cmp_points)> newNodes(cmp_points);
942 map<Edge, Cell*, decltype(cmp_edges)> edgeOwners(cmp_edges);
947 Edge edge(*edge_cit, *
next(edge_cit));
948 edgeOwners[edge] = m_mesh->FindEdgeNeighbor(cell, edge);
949 }
while (++edge_cit != cell->
GetNodes().begin());
951 list<QPointF> points;
953 points.push_back(QPointF((*node)[0], (*node)[1]));
954 newNodes[QPointF((*node)[0], (*node)[1])] = node;
957 for (
const QPolygonF& polygon : newCells) {
958 vector<unsigned int> nodeIDs;
959 for (
const QPointF& point : polygon) {
960 points.push_back(point);
962 if (newNodes.find(point) == newNodes.end()) {
963 newNodes[point] = m_mesh->BuildNode({{point.x(), point.y(), 0}},
false);
965 nodeIDs.push_back(newNodes[point]->GetIndex());
968 Cell* c = m_mesh->BuildCell(nodeIDs);
969 c->CellAttributes::operator=(*cell);
973 std::list<Wall*> newWalls;
974 Node* endpoint =
nullptr;
975 for (
const QPolygonF& polygon : newCells) {
976 auto polygonStd = polygon.toStdVector();
981 QPointF cell_p1((**cell_cit)[0], (**cell_cit)[1]);
982 QPointF cell_p2((**
next(cell_cit))[0], (**
next(cell_cit))[1]);
983 QLineF cell_line = perturb_line(QLineF(cell_p1, cell_p2));
985 QLineF polygon_line = perturb_line(QLineF(*polygon_cit, *
next(polygon_cit)));
987 QPointF intersection;
988 if (polygon_line.intersect(cell_line, &intersection) == QLineF::BoundedIntersection) {
989 if (is_perturbed(intersection, *polygon_cit)) {
990 intersection = *polygon_cit;
991 assert(newNodes.find(intersection) != newNodes.end()
992 &&
"All intersections should already have been added.");
994 else if (is_perturbed(intersection, *
next(polygon_cit))) {
995 intersection = *
next(polygon_cit);
996 assert(newNodes.find(intersection) != newNodes.end()
997 &&
"All intersections should already have been added.");
1003 if (intersection != cell_p1 && intersection != cell_p2) {
1004 Edge edge(*cell_cit, *
next(cell_cit));
1005 Edge edge1(*cell_cit, newNodes[intersection]);
1006 Edge edge2(newNodes[intersection], *
next(cell_cit));
1007 Cell* neighbor = edgeOwners[edge];
1009 if (m_mesh->GetWalls().size() == 0 && endpoint ==
nullptr) {
1010 endpoint = newNodes[intersection];
1012 else if (m_mesh->GetWalls().size() == 0) {
1013 Wall* newWall = m_mesh->BuildWall(newNodes[intersection], endpoint, cell, m_mesh->GetBoundaryPolygon());
1014 cell->AddWall(newWall);
1015 neighbor->AddWall(newWall);
1016 newWalls.push_back(newWall);
1017 newWall = m_mesh->BuildWall(endpoint, newNodes[intersection], cell, m_mesh->GetBoundaryPolygon());
1018 cell->AddWall(newWall);
1019 neighbor->AddWall(newWall);
1020 newWalls.push_back(newWall);
1023 auto wall = find_if(cell->
GetWalls().begin(), cell->
GetWalls().end(), [edge](
Wall* w){
return w->IncludesEdge(edge);});
1024 assert(wall != cell->
GetWalls().end()
1025 && find_if(
next(wall), cell->
GetWalls().end(), [edge](
Wall* w){
return w->IncludesEdge(edge);}) == cell->
GetWalls().end()
1026 &&
"There should be exactly one wall associated with this edge.");
1030 if ((*wall)->GetC1() == cell) {
1031 newWall = m_mesh->BuildWall(newNodes[intersection], (*wall)->GetN2(), cell, neighbor);
1034 newWall = m_mesh->BuildWall(newNodes[intersection], (*wall)->GetN2(), neighbor, cell);
1036 (*wall)->SetN2(newNodes[intersection]);
1037 (*wall)->SetLengthDirty();
1038 cell->AddWall(newWall);
1039 neighbor->AddWall(newWall);
1041 newWalls.push_back(*wall);
1042 newWalls.push_back(newWall);
1045 edgeOwners[edge1] = neighbor;
1046 edgeOwners[edge2] = neighbor;
1047 edgeOwners.erase(edge);
1050 m_mesh->AddNodeToCell(neighbor, newNodes[intersection], *
next(cell_cit), *cell_cit);
1053 m_mesh->AddNodeToCell(neighbor, newNodes[intersection], *cell_cit, *
next(cell_cit));
1055 m_mesh->AddNodeToCell(cell, newNodes[intersection], *cell_cit, *
next(cell_cit));
1057 cell_cit = cell->
GetNodes().begin();
1059 else if (newNodes.find(*polygon_cit) != newNodes.end() && newNodes.find(*
next(polygon_cit)) != newNodes.end()) {
1060 Edge polygon_edge(newNodes[*polygon_cit], newNodes[*
next(polygon_cit)]);
1062 if (!cell->HasEdge(polygon_edge)) {
1065 Edge edge(*cell_cit, *
next(cell_cit));
1066 Cell* neighbor = edgeOwners[edge];
1068 if (m_mesh->GetWalls().size() == 0 && endpoint ==
nullptr) {
1069 endpoint = newNodes[intersection];
1071 else if (m_mesh->GetWalls().size() == 0) {
1072 if (endpoint != newNodes[intersection]) {
1073 Wall* newWall = m_mesh->BuildWall(newNodes[intersection], endpoint, cell, m_mesh->GetBoundaryPolygon());
1074 cell->AddWall(newWall);
1075 neighbor->AddWall(newWall);
1076 newWalls.push_back(newWall);
1077 newWall = m_mesh->BuildWall(endpoint, newNodes[intersection], cell, m_mesh->GetBoundaryPolygon());
1078 cell->AddWall(newWall);
1079 neighbor->AddWall(newWall);
1080 newWalls.push_back(newWall);
1084 auto wall = find_if(cell->
GetWalls().begin(), cell->
GetWalls().end(), [edge](
Wall* w){
return w->IncludesEdge(edge);});
1085 assert(wall != cell->
GetWalls().end()
1086 && find_if(
next(wall), cell->
GetWalls().end(), [edge](
Wall* w){
return w->IncludesEdge(edge);}) == cell->
GetWalls().end()
1087 &&
"There should be exactly one wall associated with this edge.");
1089 if ((*wall)->GetN1() != newNodes[intersection] && (*wall)->GetN2() != newNodes[intersection]) {
1091 if ((*wall)->GetC1() == cell) {
1092 newWall = m_mesh->BuildWall(newNodes[intersection], (*wall)->GetN2(), cell, neighbor);
1095 newWall = m_mesh->BuildWall(newNodes[intersection], (*wall)->GetN2(), neighbor, cell);
1097 (*wall)->SetN2(newNodes[intersection]);
1098 (*wall)->SetLengthDirty();
1099 cell->AddWall(newWall);
1100 neighbor->AddWall(newWall);
1102 newWalls.push_back(*wall);
1103 newWalls.push_back(newWall);
1109 }
while (++cell_cit != cell->
GetNodes().begin());
1110 }
while (++polygon_cit != polygonStd.begin());
1114 for (
const auto& n : newNodes) {
1115 m_mesh->GetNodeOwningNeighbors(n.second).remove_if(
1120 for (
const auto& w : newWalls) {
1121 m_mesh->UpdateNodeOwningWalls(w);
1125 map<Edge, Cell*, decltype(cmp_edges)> neighbors(cmp_edges);
1126 for (
Cell* c : cells) {
1130 Edge reversedEdge(*
next(c_cit), *c_cit);
1133 [edge](
Wall* w){
return w->IncludesEdge(edge);});
1134 if (wall != cell->
GetWalls().end()) {
1136 [edge](
Wall* w){
return w->IncludesEdge(edge);})
1138 &&
"There should be exactly one wall associated with this edge.");
1140 if ((*wall)->GetC1() == cell) {
1146 cell->ReassignWall(*wall, c);
1147 m_mesh->UpdateNodeOwningWalls(*wall);
1149 else if (edgeOwners.find(edge) == edgeOwners.end()
1150 && edgeOwners.find(reversedEdge) == edgeOwners.end()) {
1151 if (neighbors.find(reversedEdge) == neighbors.end()
1152 && neighbors.find(edge) == neighbors.end()) {
1153 neighbors[edge] = c;
1156 Edge owner = (neighbors.find(edge) != neighbors.end()
1157 ? edge : reversedEdge);
1159 Cell* neighbor = neighbors[owner];
1160 neighbors.erase(owner);
1165 c->AddWall(newWall);
1166 neighbor->AddWall(newWall);
1167 m_mesh->UpdateNodeOwningWalls(newWall);
1170 }
while (++c_cit != c->GetNodes().begin());
1173 m_mesh->RemoveFromNeighborList(cell);
1176 for (
const auto& n : newNodes) {
1177 SetAtBoundary(n.second);
1181 for (
Cell* c : cells) {
1182 m_mesh->ConstructNeighborList(c);
1185 list<Cell*> neighborCells;
1186 for (
const auto& owner : edgeOwners) {
1187 auto neighbor = find(neighborCells.begin(), neighborCells.end(), owner.second);
1188 if (neighbor == neighborCells.end()) {
1189 m_mesh->ConstructNeighborList(owner.second);
1190 neighborCells.push_front(owner.second);
1194 auto meshCell = find_if(m_mesh->GetCells().begin(), m_mesh->GetCells().end(),
1195 [cell](
Cell* c){
return c == cell;});
1196 m_mesh->GetCells().erase(meshCell);
1202 void EditableMesh::SetAtBoundary(
Node* node)
1204 auto boundary = find_if(
1205 m_mesh->GetNodeOwningNeighbors(node).begin(),
1206 m_mesh->GetNodeOwningNeighbors(node).end(),
1207 [](
const NeighborNodes& nb){
return nb.GetCell()->GetIndex() == -1;});
1208 node->SetAtBoundary(boundary != m_mesh->GetNodeOwningNeighbors(node).end());
1213 assert(m_mesh->GetEdgeOwners(edge).size() > 0 &&
"Edge doesn't exist in the mesh.");
1215 Wall* wall = m_mesh->FindWall(edge);
1217 for (
NeighborNodes neighbor : m_mesh->GetEdgeOwners(edge)) {
1218 if (find(neighbor.GetCell()->GetNodes().begin(), neighbor.GetCell()->GetNodes().end(), node) == neighbor.GetCell()->GetNodes().end()) {
1219 m_mesh->AddNodeToCell(neighbor.GetCell(), node, edge.
GetFirst(), edge.
GetSecond());
1223 if (m_mesh->GetWalls().size() > 0) {
1224 m_mesh->UpdateNodeOwningWalls(wall);
1233 QLineF cut((*node1)[0], (*node1)[1], (*node2)[0], (*node2)[1]);
1236 for (
auto nb : m_mesh->GetNodeOwningNeighbors(node1)) {
1237 if (nb.GetCell()->GetIndex() != -1) {
1238 owners.push_back(nb.GetCell());
1241 for (
auto nb : m_mesh->GetNodeOwningNeighbors(node2)) {
1242 if (nb.GetCell()->GetIndex() != -1) {
1243 owners.push_back(nb.GetCell());
1246 owners.sort([](
Cell* c1,
Cell* c2) {
return c1 < c2;});
1248 auto eql = [](
Cell* c1,
Cell* c2) {
1252 list<Cell*> commonOwners;
1253 auto owner = adjacent_find(owners.begin(), owners.end(), eql);
1254 while (owner != owners.end()) {
1255 commonOwners.push_back(*owner);
1256 owner = adjacent_find(++owner, owners.end(), eql);
1259 if (commonOwners.empty()) {
1260 return vector<Cell*>();
1263 list<Cell*> possibilities;
1264 for (
Cell* c : commonOwners) {
1266 for (
Node* n : c->GetNodes()) {
1267 polygon.push_back(QPointF((*n)[0], (*n)[1]));
1271 if (polygons.size() == 2) {
1272 possibilities.push_back(c);
1275 assert(possibilities.size() == 1 &&
"There can only be one cell that can be split.");
1277 auto cell = find_if(m_mesh->GetCells().begin(), m_mesh->GetCells().end(),
1278 [possibilities](
Cell* c){
return c == possibilities.front();});
1285 assert(cell !=
nullptr && node1 !=
nullptr
1286 && node2 !=
nullptr &&
"The input isn't properly initialized.");
1288 vector<Cell*> newCells;
1295 for (
NeighborNodes nb : m_mesh->GetNodeOwningNeighbors(node1)) {
1296 if (nb.GetNb1() == node2 || nb.GetNb2() == node2) {
1297 newCells.push_back(cell);
1305 QLineF cut((*node1)[0], (*node1)[1], (*node2)[0], (*node2)[1]);
1308 QPointF point1((**cit)[0], (**cit)[1]);
1309 QPointF point2((**
next(cit))[0], (**
next(cit))[1]);
1310 QPointF intersection;
1311 if (cut.intersect(QLineF(point1, point2), &intersection) == QLineF::BoundedIntersection
1312 && intersection != point1 && intersection != point2) {
1313 newCells.push_back(cell);
1316 }
while (++cit != cell->
GetNodes().begin());
1320 for (
Cell* c : cellDivider.GeometricSplitCell(cell, node1, node2)) {
1321 auto newCell = find_if(m_mesh->GetCells().begin(), m_mesh->GetCells().end(),
1322 [c](
Cell* c2){
return c2 == c; });
1323 assert(newCell != m_mesh->GetCells().end() &&
"The new cell can't be found in the mesh.");
1324 newCells.push_back(*newCell);
bool IsDeletableNode(Node *node) const
Checks whether the given node is deletable.
Interface for CellDivider.
A cell contains walls and nodes.
Namespace for SimPT tissue editor package.
Cell * GetCell() const
Return the cell of this Neighbor pair.
Combo header for circular iterator.
Interface for EditableMesh.
bool CheckAll() const
Runs all of the of checks to verify consistency of the mesh.
const std::list< Wall * > & GetWalls() const
Access the cell's walls.
Interface for NeighborNodes.
static bool IsClockwise(const QPolygonF &polygon)
Checks whether the vertices of a polygon are ordered clockwise or counterclockwise.
Cell * CreateCell(Node *node1, Node *node2, const QPointF &newPoint)
Creates a new cell with the two given nodes and a third new point.
static std::list< QPolygonF > SlicePolygon(const QPolygonF &polygon, QLineF cut)
Slice an open, simple and valid polygon in multiple polygons with a given line.
CircularIterator< typename T::iterator > make_circular(T &c)
Helper produces non-const circular iterator whose range corresponds to the begin and end iterators of...
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.
bool IsDeletableCell(Cell *cell) const
Checks whether the given cell is deletable (the mesh should stay consistent).
Namespace for container related classes.
Interface for WallAttributes.
Interface for PBMBBuilder.
Class for handling cell division.
Class that directs ptree based mesh building process.
Node * GetNb1() const
Return first node of this Neighbor pair.
bool CanSplitCell(Node *node1, Node *node2, Cell *cell=nullptr) const
Checks whether the two given nodes can split a (given) cell (excluding the boundary polygon)...
std::shared_ptr< SimPT_Sim::Mesh > & GetMesh()
Get the mesh.
Structure of neighboring nodes: two neighboring nodes from standpoint of a given cell with an orderin...
void DeleteCells(const std::list< Cell * > &cells)
Deletes the given cell from the mesh.
~EditableMesh()
Destructor.
Node * GetFirst() const
Get the first node of the edge.
const std::vector< Node * > & GetNodes() const
Access the nodes of cell's polygon.
std::vector< Cell * > SplitCell(Node *node1, Node *node2)
Does the same as SplitCell, but finds the correct cell that should be split.
int GetIndex() const
Return the index.
Node * GetNb2() const
Return second node of this Neighbor pair.
bool DisplaceNode(Node *node, double x, double y)
Place a node at the given coordinates.
CircularIterator< T > next(CircularIterator< T > i)
Helper yields the position the iterator would have if moved forward (in circular fashion) by 1 positi...
Interface for CellAttributes.
ConstCircularIterator< typename T::const_iterator > make_const_circular(const T &c)
Helper produces const circular iterator whose range corresponds to the begin and end iterators of a c...
static bool IsSimplePolygon(const QPolygonF &polygon)
Checks whether a polygon is simple.
Interface for PolygonUtils.
Node * SplitEdge(const Edge &edge)
Split a given edge at the center.
EditableMesh(const boost::property_tree::ptree &pt)
Constructor.
CircularIterator< T > prev(CircularIterator< T > i)
Helper yields the position the iterator would have if moved backward (in circular fashion) by 1 posit...
A cell wall, runs between cell corner points and consists of wall elements.
Node * GetSecond() const
Get the second node of the edge.
void ReplaceCell(Cell *cell, std::list< QPolygonF > newCells)
Replace a given cell with a set of new cells.