improved VMD class
[engrid.git] / operation.cpp
bloba65af2b4afd43cba903b8b3a09dd0f34d0e71d0d
1 //
2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 // + +
4 // + This file is part of enGrid. +
5 // + +
6 // + Copyright 2008,2009 Oliver Gloth +
7 // + +
8 // + enGrid is free software: you can redistribute it and/or modify +
9 // + it under the terms of the GNU General Public License as published by +
10 // + the Free Software Foundation, either version 3 of the License, or +
11 // + (at your option) any later version. +
12 // + +
13 // + enGrid is distributed in the hope that it will be useful, +
14 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
15 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
16 // + GNU General Public License for more details. +
17 // + +
18 // + You should have received a copy of the GNU General Public License +
19 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
20 // + +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 #include "operation.h"
24 #include "guimainwindow.h"
25 #include "vtkTriangleFilter.h"
26 #include "vtkInformation.h"
27 #include "vtkInformationVector.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkPointData.h"
30 #include "vtkPolyData.h"
31 #include "vtkPolygon.h"
32 #include "vtkStreamingDemandDrivenPipeline.h"
33 #include "vtkCellArray.h"
34 #include "vtkCellData.h"
35 #include "vtkCellLocator.h"
36 #include "vtkFloatArray.h"
37 #include "vtkMath.h"
38 #include <vtkCharArray.h>
40 #include "geometrytools.h"
41 using namespace GeometryTools;
43 #include <QApplication>
45 QSet<Operation*> Operation::garbage_operations;
47 void Operation::collectGarbage()
49 QSet<Operation*> delete_operations;
50 foreach (Operation *op, garbage_operations) {
51 if (!op->getThread().isRunning()) {
52 delete_operations.insert(op);
53 cout << "deleting Operation " << op << endl;
54 delete op;
57 foreach (Operation *op, delete_operations) {
58 garbage_operations.remove(op);
62 Operation::Operation()
64 grid = NULL;
65 gui = false;
66 err = NULL;
67 autoset = true;
70 Operation::~Operation()
72 if (err) {
73 err->display();
74 delete err;
78 void Operation::del()
80 garbage_operations.insert(this);
83 void OperationThread::run()
85 try {
86 GuiMainWindow::lock();
87 GuiMainWindow::pointer()->setBusy();
88 op->operate();
89 } catch (Error err) {
90 op->err = new Error();
91 *(op->err) = err;
93 GuiMainWindow::unlock();
94 GuiMainWindow::pointer()->setIdle();
97 void Operation::operator()()
99 if (gui) {
100 if (GuiMainWindow::tryLock()) {
101 checkGrid();
102 thread.setOperation(this);
103 GuiMainWindow::unlock();
104 thread.start(QThread::LowPriority);
105 } else {
106 QMessageBox::warning(NULL, "not permitted", "Operation is not permitted while background process is running!");
108 } else {
109 checkGrid();
110 operate();
113 checkGrid();
114 operate();
118 void Operation::setAllCells()
120 QVector<vtkIdType> all_cells;
121 getAllCells(all_cells, grid);
122 setCells(all_cells);
125 void Operation::setAllVolumeCells()
127 QVector<vtkIdType> cells;
128 getAllVolumeCells(cells, grid);
129 setCells(cells);
132 void Operation::setAllSurfaceCells()
134 QVector<vtkIdType> cells;
135 getAllSurfaceCells(cells, grid);
136 setCells(cells);
139 void Operation::initMapping()
141 nodes_map.resize(nodes.size());
142 for (int i_nodes = 0; i_nodes < nodes.size(); ++i_nodes) {
143 nodes_map[i_nodes] = nodes[i_nodes];
145 cells_map.resize(cells.size());
146 for (int i_cells = 0; i_cells < cells.size(); ++i_cells) {
147 cells_map[i_cells] = cells[i_cells];
151 void Operation::checkGrid()
153 if (grid == NULL) {
154 grid = GuiMainWindow::pointer()->getGrid();
156 if ((cells.size() == 0) && autoset) {
157 setAllCells();
161 void Operation::updateActors()
163 mainWindow()->updateActors();
166 GuiMainWindow* Operation::mainWindow()
168 return GuiMainWindow::pointer();
171 void Operation::populateBoundaryCodes(QListWidget *lw)
173 QSet<int> bcs;
174 mainWindow()->getAllBoundaryCodes(bcs);
175 foreach(int bc, bcs) {
176 QListWidgetItem *lwi = new QListWidgetItem(lw);
177 lwi->setCheckState(Qt::Unchecked);
178 QString text = "";
179 QTextStream ts(&text);
180 ts << bc;
181 lwi->setText(text);
182 lwi->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
186 stencil_t Operation::getStencil(vtkIdType id_cell1, int j1)
188 stencil_t S;
189 S.valid = true;
190 S.id_cell1 = id_cell1;
191 if (c2c[_cells[id_cell1]][j1] != -1) {
192 S.id_cell2 = cells[c2c[_cells[id_cell1]][j1]];
193 if (grid->GetCellType(S.id_cell2) != VTK_TRIANGLE) {
194 EG_BUG;
196 vtkIdType N1, N2, *pts1, *pts2;
197 grid->GetCellPoints(S.id_cell1, N1, pts1);
198 grid->GetCellPoints(S.id_cell2, N2, pts2);
199 if (j1 == 0) { S.p[0] = pts1[2]; S.p[1] = pts1[0]; S.p[3] = pts1[1]; }
200 else if (j1 == 1) { S.p[0] = pts1[0]; S.p[1] = pts1[1]; S.p[3] = pts1[2]; }
201 else if (j1 == 2) { S.p[0] = pts1[1]; S.p[1] = pts1[2]; S.p[3] = pts1[0]; };
202 bool p2 = false;
203 if (c2c[_cells[S.id_cell2]][0] != -1) {
204 if (cells[c2c[_cells[S.id_cell2]][0]] == S.id_cell1) {
205 S.p[2] = pts2[2];
206 p2 = true;
209 if (c2c[_cells[S.id_cell2]][1] != -1) {
210 if (cells[c2c[_cells[S.id_cell2]][1]] == S.id_cell1) {
211 S.p[2] = pts2[0];
212 p2 = true;
215 if (c2c[_cells[S.id_cell2]][2] != -1) {
216 if (cells[c2c[_cells[S.id_cell2]][2]] == S.id_cell1) {
217 S.p[2] = pts2[1];
218 p2 = true;
221 if (!p2) {
222 EG_BUG;
224 } else {
225 S.valid = false;
226 S.id_cell2 = -1;
227 vtkIdType N1, *pts1;
228 grid->GetCellPoints(S.id_cell1, N1, pts1);
229 if (j1 == 0) { S.p[0] = pts1[2]; S.p[1] = pts1[0]; S.p[3] = pts1[1]; }
230 else if (j1 == 1) { S.p[0] = pts1[0]; S.p[1] = pts1[1]; S.p[3] = pts1[2]; }
231 else if (j1 == 2) { S.p[0] = pts1[1]; S.p[1] = pts1[2]; S.p[3] = pts1[0]; };
233 return S;
236 ostream& operator<<(ostream &out, stencil_t S)
238 out<<"S.id_cell1="<<S.id_cell1<<" ";
239 out<<"S.id_cell2="<<S.id_cell2<<" ";
240 out<<"S.valid="<<S.valid<<" ";
241 out<<"[";
242 for(int i=0;i<4;i++){
243 out<<S.p[i];
244 if(i!=3) out<<",";
246 out<<"]";
247 return(out);
250 //////////////////////////////////////////////
251 double CurrentVertexAvgDist(vtkIdType a_vertex,QVector< QSet< int > > &n2n,vtkUnstructuredGrid *a_grid)
253 double total_dist=0;
254 double avg_dist=0;
255 int N=n2n[a_vertex].size();
256 vec3_t C;
257 a_grid->GetPoint(a_vertex, C.data());
258 foreach(int i,n2n[a_vertex])
260 vec3_t M;
261 a_grid->GetPoint(i, M.data());
262 total_dist+=(M-C).abs();
264 avg_dist=total_dist/(double)N;
265 return(avg_dist);
268 double CurrentMeshDensity(vtkIdType a_vertex,QVector< QSet< int > > &n2n,vtkUnstructuredGrid *a_grid)
270 double total_dist=0;
271 double avg_dist=0;
272 int N=n2n[a_vertex].size();
273 vec3_t C;
274 a_grid->GetPoint(a_vertex, C.data());
275 foreach(int i,n2n[a_vertex])
277 vec3_t M;
278 a_grid->GetPoint(i, M.data());
279 total_dist+=(M-C).abs();
281 avg_dist=total_dist/(double)N;
282 double avg_density=1./avg_dist;
283 return(avg_density);
286 double DesiredVertexAvgDist(vtkIdType a_vertex,QVector< QSet< int > > &n2n,vtkUnstructuredGrid *a_grid)
288 double total_dist=0;
289 double avg_dist=0;
290 EG_VTKDCN(vtkDoubleArray, node_meshdensity, a_grid, "node_meshdensity");
291 int N=n2n[a_vertex].size();
292 foreach(int i,n2n[a_vertex])
294 total_dist+=1./node_meshdensity->GetValue(i);
296 avg_dist=total_dist/(double)N;
297 return(avg_dist);
300 double DesiredMeshDensity(vtkIdType a_vertex,QVector< QSet< int > > &n2n,vtkUnstructuredGrid *a_grid)
302 double total_density=0;
303 double avg_density=0;
304 EG_VTKDCN(vtkDoubleArray, node_meshdensity, a_grid, "node_meshdensity");
305 int N=n2n[a_vertex].size();
306 foreach(int i,n2n[a_vertex])
308 total_density+=node_meshdensity->GetValue(i);
310 avg_density=total_density/(double)N;
311 return(avg_density);
314 ///////////////////////////////////////////
315 vtkIdType Operation::getClosestNode(vtkIdType a_id_node,vtkUnstructuredGrid* a_grid)
317 vec3_t C;
318 a_grid->GetPoint(a_id_node,C.data());
319 vtkIdType id_minlen=-1;
320 double minlen=-1;
321 foreach(vtkIdType neighbour,n2n[a_id_node])
323 vec3_t M;
324 a_grid->GetPoint(neighbour,M.data());
325 double len=(M-C).abs();
326 if(minlen<0 or len<minlen)
328 minlen=len;
329 id_minlen=neighbour;
332 return(id_minlen);
335 vtkIdType Operation::getFarthestNode(vtkIdType a_id_node,vtkUnstructuredGrid* a_grid)
337 vec3_t C;
338 a_grid->GetPoint(a_id_node,C.data());
339 vtkIdType id_maxlen=-1;
340 double maxlen=-1;
341 foreach(vtkIdType neighbour,n2n[a_id_node])
343 vec3_t M;
344 a_grid->GetPoint(neighbour,M.data());
345 double len=(M-C).abs();
346 if(maxlen<0 or len>maxlen)
348 maxlen=len;
349 id_maxlen=neighbour;
352 return(id_maxlen);
355 bool Operation::SwapCells(vtkUnstructuredGrid* a_grid, stencil_t S)
357 bool swap = false;
358 if (S.valid) {
359 vec3_t x3[4], x3_0(0,0,0);
360 vec2_t x[4];
361 for (int k = 0; k < 4; ++k) {
362 a_grid->GetPoints()->GetPoint(S.p[k], x3[k].data());
363 x3_0 += x3[k];
365 vec3_t n1 = triNormal(x3[0], x3[1], x3[3]);
366 vec3_t n2 = triNormal(x3[1], x3[2], x3[3]);
367 n1.normalise();
368 n2.normalise();
369 if ( (n1*n2) > 0.8) {
370 vec3_t n = n1 + n2;
371 n.normalise();
372 vec3_t ex = orthogonalVector(n);
373 vec3_t ey = ex.cross(n);
374 for (int k = 0; k < 4; ++k) {
375 x[k] = vec2_t(x3[k]*ex, x3[k]*ey);
377 vec2_t r1, r2, r3, u1, u2, u3;
378 r1 = 0.5*(x[0] + x[1]); u1 = turnLeft(x[1] - x[0]);
379 r2 = 0.5*(x[1] + x[2]); u2 = turnLeft(x[2] - x[1]);
380 r3 = 0.5*(x[1] + x[3]); u3 = turnLeft(x[3] - x[1]);
381 double k, l;
382 vec2_t xm1, xm2;
383 bool ok = true;
384 if (intersection(k, l, r1, u1, r3, u3)) {
385 xm1 = r1 + k*u1;
386 if (intersection(k, l, r2, u2, r3, u3)) {
387 xm2 = r2 + k*u2;
388 } else {
389 ok = false;
391 } else {
392 ok = false;
393 swap = true;
395 if (ok) {
396 if ((xm1 - x[2]).abs() < (xm1 - x[0]).abs()) {
397 swap = true;
399 if ((xm2 - x[0]).abs() < (xm2 - x[2]).abs()) {
400 swap = true;
405 if (swap) {
406 vtkIdType new_pts1[3], new_pts2[3];
407 new_pts1[0] = S.p[1];
408 new_pts1[1] = S.p[2];
409 new_pts1[2] = S.p[0];
410 new_pts2[0] = S.p[2];
411 new_pts2[1] = S.p[3];
412 new_pts2[2] = S.p[0];
413 a_grid->ReplaceCell(S.id_cell1, 3, new_pts1);
414 a_grid->ReplaceCell(S.id_cell2, 3, new_pts2);
416 return(swap);
419 void Operation::quad2triangle(vtkUnstructuredGrid* src,vtkIdType quadcell)
421 vtkIdType type_cell = grid->GetCellType(quadcell);
422 cout<<"It's a "<<type_cell<<endl;
423 if(type_cell==VTK_QUAD)
425 cout_grid(cout,src,true,true,true,true);
426 EG_VTKSP(vtkUnstructuredGrid, dst);
427 //src grid info
428 int N_points=src->GetNumberOfPoints();
429 int N_cells=src->GetNumberOfCells();
430 allocateGrid(dst,N_cells+1,N_points);
432 for (vtkIdType id_node = 0; id_node < src->GetNumberOfPoints(); ++id_node) {
433 vec3_t x;
434 src->GetPoints()->GetPoint(id_node, x.data());
435 dst->GetPoints()->SetPoint(id_node, x.data());
436 copyNodeData(src, id_node, dst, id_node);
438 for (vtkIdType id_cell = 0; id_cell < src->GetNumberOfCells(); ++id_cell) {
439 vtkIdType N_pts, *pts;
440 vtkIdType type_cell = src->GetCellType(id_cell);
441 src->GetCellPoints(id_cell, N_pts, pts);
442 vtkIdType id_new_cell;
443 vtkIdType id_new_cell1;
444 vtkIdType id_new_cell2;
445 if(id_cell!=quadcell)
447 id_new_cell = dst->InsertNextCell(type_cell, N_pts, pts);
448 copyCellData(src, id_cell, dst, id_new_cell);
450 else
452 vtkIdType triangle1[3];
453 vtkIdType triangle2[3];
454 triangle1[0]=pts[1];
455 triangle1[1]=pts[3];
456 triangle1[2]=pts[0];
457 triangle2[0]=pts[3];
458 triangle2[1]=pts[1];
459 triangle2[2]=pts[2];
460 id_new_cell1 = dst->InsertNextCell(VTK_TRIANGLE, 3, triangle1);
461 copyCellData(src, id_cell, dst, id_new_cell1);
462 id_new_cell2 = dst->InsertNextCell(VTK_TRIANGLE, 3, triangle2);
463 copyCellData(src, id_cell, dst, id_new_cell2);
464 stencil_t S;
465 S.id_cell1=id_new_cell1;
466 S.id_cell2=id_new_cell2;
467 S.p[0]=pts[0];
468 S.p[1]=pts[1];
469 S.p[2]=pts[2];
470 S.p[3]=pts[3];
471 S.valid=true;
472 SwapCells(dst,S);
475 cout_grid(cout,dst,true,true,true,true);
476 makeCopy(dst, src);
477 }//end of if quad
480 void Operation::quad2triangle(vtkUnstructuredGrid* src,vtkIdType quadcell,vtkIdType MovingPoint)
482 vtkIdType type_cell = grid->GetCellType(quadcell);
483 cout<<"It's a "<<type_cell<<endl;
484 if(type_cell==VTK_QUAD)
486 cout_grid(cout,src,true,true,true,true);
487 EG_VTKSP(vtkUnstructuredGrid, dst);
488 //src grid info
489 int N_points=src->GetNumberOfPoints();
490 int N_cells=src->GetNumberOfCells();
491 allocateGrid(dst,N_cells+1,N_points);
493 for (vtkIdType id_node = 0; id_node < src->GetNumberOfPoints(); ++id_node) {
494 vec3_t x;
495 src->GetPoints()->GetPoint(id_node, x.data());
496 dst->GetPoints()->SetPoint(id_node, x.data());
497 copyNodeData(src, id_node, dst, id_node);
499 for (vtkIdType id_cell = 0; id_cell < src->GetNumberOfCells(); ++id_cell) {
500 vtkIdType N_pts, *pts;
501 src->GetCellPoints(id_cell, N_pts, pts);
502 vtkIdType type_cell = src->GetCellType(id_cell);
503 vtkIdType id_new_cell;
504 vtkIdType id_new_cell1;
505 vtkIdType id_new_cell2;
506 if(id_cell!=quadcell)
508 id_new_cell = dst->InsertNextCell(type_cell, N_pts, pts);
509 copyCellData(src, id_cell, dst, id_new_cell);
511 else
513 vtkIdType triangle1[3];
514 vtkIdType triangle2[3];
515 if(MovingPoint==pts[0] || MovingPoint==pts[2])
517 triangle1[0]=pts[1];
518 triangle1[1]=pts[3];
519 triangle1[2]=pts[0];
520 triangle2[0]=pts[3];
521 triangle2[1]=pts[1];
522 triangle2[2]=pts[2];
524 else
526 triangle1[0]=pts[2];
527 triangle1[1]=pts[0];
528 triangle1[2]=pts[1];
529 triangle2[0]=pts[0];
530 triangle2[1]=pts[2];
531 triangle2[2]=pts[3];
533 id_new_cell1 = dst->InsertNextCell(VTK_TRIANGLE, 3, triangle1);
534 copyCellData(src, id_cell, dst, id_new_cell1);
535 id_new_cell2 = dst->InsertNextCell(VTK_TRIANGLE, 3, triangle2);
536 copyCellData(src, id_cell, dst, id_new_cell2);
539 cout_grid(cout,dst,true,true,true,true);
540 makeCopy(dst, src);
541 }//end of if quad
544 int Operation::NumberOfCommonPoints(vtkIdType node1, vtkIdType node2, bool& IsTetra)
546 // QVector< QSet< int > > n2n
547 QSet <int> node1_neighbours=n2n[node1];
548 QSet <int> node2_neighbours=n2n[node2];
549 QSet <int> intersection=node1_neighbours.intersect(node2_neighbours);
550 int N=intersection.size();
551 IsTetra=false;
552 if(N==2)
554 QSet<int>::const_iterator p1=intersection.begin();
555 QSet<int>::const_iterator p2=p1+1;
556 vtkIdType intersection1=_nodes[*p1];
557 vtkIdType intersection2=_nodes[*p2];
558 if(n2n[intersection1].contains(intersection2))//if there's an edge between intersection1 and intersection2
560 //check if (node1,intersection1,intersection2) and (node2,intersection1,intersection2) are defined as cells!
561 // QVector< QSet< int > > n2c
562 QSet< int > S1=n2c[intersection1];
563 QSet< int > S2=n2c[intersection2];
564 QSet< int > Si=S1.intersect(S2);
565 int counter=0;
566 foreach(vtkIdType C,Si){
567 vtkIdType N_pts, *pts;
568 grid->GetCellPoints(C, N_pts, pts);
569 for(int i=0;i<N_pts;i++)
571 if(pts[i]==node1 || pts[i]==node2) counter++;
574 if(counter>=2) IsTetra=true;
577 return(N);
580 // vtkIdType Operation::FindSnapPoint(vtkUnstructuredGrid *src, vtkIdType DeadNode)
581 // {
582 // return(0);
583 // }
585 bool Operation::DeletePoint(vtkUnstructuredGrid *src, vtkIdType DeadNode)
587 EG_VTKSP(vtkUnstructuredGrid, dst);
589 //src grid info
590 int N_points=src->GetNumberOfPoints();
591 int N_cells=src->GetNumberOfCells();
592 int N_newpoints=-1;
593 int N_newcells=0;
595 if(DeadNode<0 || DeadNode>=N_points)
597 cout<<"Warning: Point out of range: DeadNode="<<DeadNode<<" N_points="<<N_points<<endl;
598 return(false);
601 QSet <vtkIdType> DeadCells;
602 QSet <vtkIdType> MutatedCells;
603 QSet <vtkIdType> MutilatedCells;
605 vtkIdType SnapPoint=-1;
606 //Find closest point to DeadNode
607 // vtkIdType SnapPoint = getClosestNode(DeadNode,src);//DeadNode moves to SnapPoint
609 foreach(vtkIdType PSP, n2n[DeadNode])
611 bool IsValidSnapPoint=true;
613 cout<<"====>PSP="<<PSP<<endl;
614 bool IsTetra=true;
615 if(NumberOfCommonPoints(DeadNode,PSP,IsTetra)>2)//common point check
617 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
618 IsValidSnapPoint=false;
620 if(IsTetra)//tetra check
622 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
623 IsValidSnapPoint=false;
626 //count number of points and cells to remove + analyse cell transformations
627 N_newpoints=-1;
628 N_newcells=0;
629 DeadCells.clear();
630 MutatedCells.clear();
631 MutilatedCells.clear();
632 foreach(vtkIdType C, n2c[DeadNode])//loop through potentially dead cells
634 cout<<"C="<<C<<endl;
635 //get points around cell
636 vtkIdType N_pts, *pts;
637 src->GetCellPoints(C, N_pts, pts);
639 bool ContainsSnapPoint=false;
640 bool invincible=false;
641 for(int i=0;i<N_pts;i++)
643 cout<<"pts["<<i<<"]="<<pts[i]<<" and PSP="<<PSP<<endl;
644 if(pts[i]==PSP) {ContainsSnapPoint=true;}
645 if(pts[i]!=DeadNode && pts[i]!=PSP && n2c[pts[i]].size()<=1) invincible=true;
647 if(ContainsSnapPoint)
649 if(N_pts==3)//dead cell
651 if(invincible)//Check that empty lines aren't left behind when a cell is killed
653 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
654 IsValidSnapPoint=false;
656 else
658 DeadCells.insert(C);
659 N_newcells-=1;
660 cout<<"cell "<<C<<" has been pwned!"<<endl;
663 /* else if(N_pts==4)//mutilated cell
665 MutilatedCells.insert(C);
666 cout<<"cell "<<C<<" has lost a limb!"<<endl;
668 else
670 cout<<"RED ALERT: Xenomorph detected!"<<endl;
671 EG_BUG;
674 else
676 vtkIdType src_N_pts, *src_pts;
677 src->GetCellPoints(C, src_N_pts, src_pts);
679 if(src_N_pts!=3)
681 cout<<"RED ALERT: Xenomorph detected!"<<endl;
682 EG_BUG;
685 vtkIdType OldTriangle[3];
686 vtkIdType NewTriangle[3];
688 for(int i=0;i<src_N_pts;i++)
690 OldTriangle[i]=src_pts[i];
691 NewTriangle[i]=( (src_pts[i]==DeadNode) ? PSP : src_pts[i] );
693 vec3_t Old_N= triNormal(src, OldTriangle[0], OldTriangle[1], OldTriangle[2]);
694 vec3_t New_N= triNormal(src, NewTriangle[0], NewTriangle[1], NewTriangle[2]);
695 double OldArea=Old_N.abs();
696 double NewArea=New_N.abs();
697 double scal=Old_N*New_N;
698 double cross=(Old_N.cross(New_N)).abs();//double-cross on Nar Shadaa B-)
700 cout<<"OldArea="<<OldArea<<endl;
701 cout<<"NewArea="<<NewArea<<endl;
702 cout<<"scal="<<scal<<endl;
703 cout<<"cross="<<cross<<endl;
705 if(Old_N*New_N<Old_N*Old_N*1./100.)//area + inversion check
707 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
708 IsValidSnapPoint=false;
711 /* if(NewArea<OldArea*1./100.)
713 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
714 IsValidSnapPoint=false;
717 if(abs(cross)>10e-4)
719 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
720 IsValidSnapPoint=false;
723 //mutated cell
724 MutatedCells.insert(C);
725 cout<<"cell "<<C<<" has been infected!"<<endl;
729 if(N_cells+N_newcells<=0)//survivor check
731 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
732 IsValidSnapPoint=false;
734 /* if(EmptyVolume(DeadNode,PSP))//simplified volume check
736 cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
737 IsValidSnapPoint=false;
739 if(IsValidSnapPoint) {SnapPoint=PSP; break;}
740 }//end of loop through potential SnapPoints
742 cout<<"===>SNAPPOINT="<<SnapPoint<<endl;
743 if(SnapPoint<0) {cout<<"Sorry no possible SnapPoint found."<<endl; return(false);}
745 //allocate
746 cout<<"N_points="<<N_points<<endl;
747 cout<<"N_cells="<<N_cells<<endl;
748 cout<<"N_newpoints="<<N_newpoints<<endl;
749 cout<<"N_newcells="<<N_newcells<<endl;
750 allocateGrid(dst,N_cells+N_newcells,N_points+N_newpoints);
752 //vector used to redefine the new point IDs
753 QVector <vtkIdType> OffSet(N_points);
755 //copy undead points
756 vtkIdType dst_id_node=0;
757 for (vtkIdType src_id_node = 0; src_id_node < N_points; src_id_node++) {//loop through src points
758 if(src_id_node!=DeadNode)//if the node isn't dead, copy it
760 vec3_t x;
761 src->GetPoints()->GetPoint(src_id_node, x.data());
762 dst->GetPoints()->SetPoint(dst_id_node, x.data());
763 copyNodeData(src, src_id_node, dst, dst_id_node);
764 OffSet[src_id_node]=src_id_node-dst_id_node;
765 dst_id_node++;
769 cout<<"DeadCells="<<DeadCells<<endl;
770 cout<<"MutatedCells="<<MutatedCells<<endl;
771 cout<<"MutilatedCells="<<MutilatedCells<<endl;
773 //Copy undead cells
774 for (vtkIdType id_cell = 0; id_cell < src->GetNumberOfCells(); ++id_cell) {//loop through src cells
775 if(!DeadCells.contains(id_cell))//if the cell isn't dead
777 vtkIdType src_N_pts, *src_pts;
778 vtkIdType dst_N_pts, *dst_pts;
779 src->GetCellPoints(id_cell, src_N_pts, src_pts);
781 vtkIdType type_cell = src->GetCellType(id_cell);
782 cout<<"-->id_cell="<<id_cell<<endl;
783 for(int i=0;i<src_N_pts;i++) cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
784 // src->GetCellPoints(id_cell, dst_N_pts, dst_pts);
785 dst_N_pts=src_N_pts;
786 dst_pts=new vtkIdType[dst_N_pts];
787 if(MutatedCells.contains(id_cell))//mutated cell
789 cout<<"processing mutated cell "<<id_cell<<endl;
790 for(int i=0;i<src_N_pts;i++)
792 if(src_pts[i]==DeadNode) {
793 cout<<"SnapPoint="<<SnapPoint<<endl;
794 cout<<"OffSet[SnapPoint]="<<OffSet[SnapPoint]<<endl;
795 cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
796 dst_pts[i]=SnapPoint-OffSet[SnapPoint];
798 else dst_pts[i]=src_pts[i]-OffSet[src_pts[i]];
800 cout<<"--->dst_pts:"<<endl;
801 for(int i=0;i<dst_N_pts;i++) cout<<"dst_pts["<<i<<"]="<<dst_pts[i]<<endl;
804 else if(MutilatedCells.contains(id_cell))//mutilated cell
806 cout<<"processing mutilated cell "<<id_cell<<endl;
808 if(type_cell==VTK_QUAD) {
809 type_cell=VTK_TRIANGLE;
810 dst_N_pts-=1;
812 else {cout<<"FATAL ERROR: Unknown mutilated cell detected! It is not a quad! Potential xenomorph infestation!"<<endl;EG_BUG;}
813 //merge points
814 int j=0;
815 for(int i=0;i<src_N_pts;i++)
817 if(src_pts[i]==SnapPoint) { dst_pts[j]=SnapPoint-OffSet[SnapPoint];j++; }//SnapPoint
818 else if(src_pts[i]!=DeadNode) { dst_pts[j]=src_pts[i]-OffSet[src_pts[i]];j++; }//pre-snap/dead + post-snap/dead
819 //do nothing in case of DeadNode
822 else//normal cell
824 cout<<"processing normal cell "<<id_cell<<endl;
825 for(int i=0;i<src_N_pts;i++)
827 dst_pts[i]=src_pts[i]-OffSet[src_pts[i]];
830 //copy the cell
831 vtkIdType id_new_cell = dst->InsertNextCell(type_cell, dst_N_pts, dst_pts);
832 copyCellData(src, id_cell, dst, id_new_cell);
833 cout<<"===Copying cell "<<id_cell<<" to "<<id_new_cell<<"==="<<endl;
834 cout<<"src_pts:"<<endl;
835 for(int i=0;i<src_N_pts;i++) cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
836 cout<<"dst_pts:"<<endl;
837 for(int i=0;i<dst_N_pts;i++) cout<<"dst_pts["<<i<<"]="<<dst_pts[i]<<endl;
838 cout<<"OffSet="<<OffSet<<endl;
839 cout<<"===Copying cell end==="<<endl;
840 delete dst_pts;
843 // cout_grid(cout,dst,true,true,true,true);
844 makeCopy(dst, src);
845 return(true);
848 bool Operation::EmptyVolume(vtkIdType DeadNode, vtkIdType PSP)
850 c2c[DeadNode];
851 c2c[PSP];
852 return(true);
855 vec3_t Operation::GetCenter(vtkIdType cellId, double& R)
857 vtkIdType *pts, Npts;
858 grid->GetCellPoints(cellId, Npts, pts);
860 vec3_t x(0,0,0);
861 for (vtkIdType i = 0; i < Npts; ++i) {
862 vec3_t xp;
863 grid->GetPoints()->GetPoint(pts[i], xp.data());
864 x += double(1)/Npts * xp;
867 R = 1e99;
868 for (vtkIdType i = 0; i < Npts; ++i) {
869 vec3_t xp;
870 grid->GetPoints()->GetPoint(pts[i], xp.data());
871 R = min(R, 0.25*(xp-x).abs());
874 return(x);
877 bool Operation::getNeighbours(vtkIdType Boss, QVector <vtkIdType>& Peons, int BC)
879 // QVector <vtkIdType> Peons;
881 QSet <int> S1=n2c[Boss];
882 cout<<"S1="<<S1<<endl;
883 foreach(vtkIdType PN,n2n[Boss])
885 cout<<"PN="<<PN<<endl;
886 QSet <int> S2=n2c[PN];
887 cout<<"S2="<<S2<<endl;
888 QSet <int> Si=S2.intersect(S1);
889 cout<<"PN="<<PN<<" Si="<<Si<<endl;
890 if(Si.size()<2)//only one common cell
892 Peons.push_back(PN);
894 else
896 QSet <int> bc_set;
897 foreach(vtkIdType C,Si)
899 EG_VTKDCC(vtkIntArray, cell_code, grid, "cell_code");
900 int bc=cell_code->GetValue(C);
901 cout<<"C="<<C<<" bc="<<bc<<endl;
902 bc_set.insert(bc);
904 if(bc_set.size()>1)//2 different boundary codes
906 Peons.push_back(PN);
910 if(Peons.size()==2)
912 /* Peon1=Peons[0];
913 Peon2=Peons[1];*/
914 return(true);
916 else
918 int N=n2n[Boss].size();
919 QVector <vtkIdType> neighbours(N);
920 qCopy(n2n[Boss].begin(), n2n[Boss].end(), neighbours.begin());
922 double alphamin_value;
923 vtkIdType alphamin_i;
924 vtkIdType alphamin_j;
925 bool first=true;
927 for(int i=0;i<N;i++)
929 for(int j=i+1;j<N;j++)
931 double alpha=deviation(grid,neighbours[i],Boss,neighbours[j]);
932 // cout<<"alpha("<<neighbours[i]<<","<<Boss<<","<<neighbours[j]<<")="<<alpha<<endl;
933 if(first) {
934 alphamin_value=alpha;
935 alphamin_i=i;
936 alphamin_j=j;
937 first=false;
939 else
941 if(alpha<alphamin_value)
943 alphamin_value=alpha;
944 alphamin_i=i;
945 alphamin_j=j;
950 // cout<<"alphamin_value="<<alphamin_value<<endl;
952 Peons.resize(2);
953 Peons[0]=neighbours[alphamin_i];
954 Peons[1]=neighbours[alphamin_j];
955 return(true);
956 /* cout<<"FATAL ERROR: number of neighbours != 2"<<endl;
957 EG_BUG;*/
959 return(false);
962 int Operation::UpdateMeshDensity()
964 cout<<"===UpdateMeshDensity START==="<<endl;
966 getAllSurfaceCells(cells,grid);
967 EG_VTKDCC(vtkIntArray, cell_code, grid, "cell_code");
968 EG_VTKDCN(vtkDoubleArray, node_meshdensity, grid, "node_meshdensity");
969 getNodesFromCells(cells, nodes, grid);
970 setGrid(grid);
971 setCells(cells);
973 if(DebugLevel>5) cout<<"cells.size()="<<cells.size()<<endl;
975 EG_VTKDCN(vtkDoubleArray, node_meshdensity_current, grid, "node_meshdensity_current");
976 foreach(vtkIdType node,nodes)
978 double L=CurrentVertexAvgDist(node,n2n,grid);
979 double D=1./L;
980 node_meshdensity_current->SetValue(node, D);
982 cout<<"===UpdateMeshDensity END==="<<endl;
983 return(0);
986 // Special structure for marking vertices
987 typedef struct _vtkMeshVertex
989 char type;
990 vtkIdList *edges; // connected edges (list of connected point ids)
991 } vtkMeshVertex, *vtkMeshVertexPtr;
993 int Operation::UpdateNodeType()
995 if(DebugLevel>47) cout<<"this->FeatureAngle="<<this->FeatureAngle<<endl;
996 if(DebugLevel>47) cout<<"this->EdgeAngle="<<this->EdgeAngle<<endl;
997 // cout<<"===UpdateNodeType START==="<<endl;
999 getAllSurfaceCells(cells,grid);
1000 if(DebugLevel>5) cout<<"cells.size()="<<cells.size()<<endl;
1002 EG_VTKSP(vtkPolyData, pdata);
1003 // addToPolyData(m_SelectedCells, pdata, grid);
1004 addToPolyData(cells, pdata, grid);
1006 vtkPolyData* input=pdata;
1008 vtkPolyData *source = 0;
1010 vtkIdType numPts, numCells, i, numPolys;
1011 int j, k;
1012 vtkIdType npts = 0;
1013 vtkIdType *pts = 0;
1014 vtkIdType p1, p2;
1015 double x[3], y[3], deltaX[3], xNew[3], conv, maxDist, dist, factor;
1016 double x1[3], x2[3], x3[3], l1[3], l2[3];
1017 double CosFeatureAngle; //Cosine of angle between adjacent polys
1018 double CosEdgeAngle; // Cosine of angle between adjacent edges
1019 double closestPt[3], dist2, *w = NULL;
1020 int iterationNumber, abortExecute;
1021 vtkIdType numSimple=0, numBEdges=0, numFixed=0, numFEdges=0;
1022 vtkPolyData *inMesh, *Mesh;
1023 vtkPoints *inPts;
1024 vtkCellArray *inVerts, *inLines, *inPolys;
1025 vtkPoints *newPts;
1026 vtkMeshVertexPtr Verts;
1027 vtkCellLocator *cellLocator=NULL;
1029 // Check input
1031 numPts=input->GetNumberOfPoints();
1032 numCells=input->GetNumberOfCells();
1033 if (numPts < 1 || numCells < 1)
1035 cout<<"No data to smooth!"<<endl;
1036 return 1;
1039 CosFeatureAngle =
1040 cos((double) vtkMath::DegreesToRadians() * this->FeatureAngle);
1041 CosEdgeAngle = cos((double) vtkMath::DegreesToRadians() * this->EdgeAngle);
1043 if(DebugLevel>5) {
1044 cout<<"Smoothing " << numPts << " vertices, " << numCells
1045 << " cells with:\n"
1046 << "\tConvergence= " << this->Convergence << "\n"
1047 << "\tIterations= " << this->NumberOfIterations << "\n"
1048 << "\tRelaxation Factor= " << this->RelaxationFactor << "\n"
1049 << "\tEdge Angle= " << this->EdgeAngle << "\n"
1050 << "\tBoundary Smoothing " << (this->BoundarySmoothing ? "On\n" : "Off\n")
1051 << "\tFeature Edge Smoothing " << (this->FeatureEdgeSmoothing ? "On\n" : "Off\n")
1052 << "\tError Scalars " << (this->GenerateErrorScalars ? "On\n" : "Off\n")
1053 << "\tError Vectors " << (this->GenerateErrorVectors ? "On\n" : "Off\n")<<endl;
1055 // Peform topological analysis. What we're gonna do is build a connectivity
1056 // array of connected vertices. The outcome will be one of three
1057 // classifications for a vertex: VTK_SIMPLE_VERTEX, VTK_FIXED_VERTEX. or
1058 // VTK_EDGE_VERTEX. Simple vertices are smoothed using all connected
1059 // vertices. FIXED vertices are never smoothed. Edge vertices are smoothed
1060 // using a subset of the attached vertices.
1062 if(DebugLevel>5) cout<<"===>Analyze topology==="<<endl;
1063 if(DebugLevel>5) cout<<"Analyzing topology..."<<endl;
1064 if(DebugLevel>5) cout<<"0:numPts="<<numPts<<endl;
1065 Verts = new vtkMeshVertex[numPts];
1066 for (i=0; i<numPts; i++)
1068 if(DebugLevel>5) cout<<"0:VTK_SIMPLE_VERTEX"<<endl;
1069 Verts[i].type = VTK_SIMPLE_VERTEX; //can smooth
1070 Verts[i].edges = NULL;
1073 inPts = input->GetPoints();
1074 conv = this->Convergence * input->GetLength();
1076 if(DebugLevel>5) cout<<"==polygons and triangle strips=="<<endl;
1077 // now polygons and triangle strips-------------------------------
1078 inPolys=input->GetPolys();
1079 numPolys = inPolys->GetNumberOfCells();
1081 if(DebugLevel>5) cout<<"numPolys="<<numPolys<<endl;
1083 if ( numPolys > 0 )
1084 { //build cell structure
1085 vtkCellArray *polys;
1086 vtkIdType cellId;
1087 int numNei, nei, edge;
1088 vtkIdType numNeiPts;
1089 vtkIdType *neiPts;
1090 double normal[3], neiNormal[3];
1091 vtkIdList *neighbors;
1093 neighbors = vtkIdList::New();
1094 neighbors->Allocate(VTK_CELL_SIZE);
1096 inMesh = vtkPolyData::New();
1097 inMesh->SetPoints(inPts);
1098 inMesh->SetPolys(inPolys);
1099 Mesh = inMesh;
1101 Mesh->BuildLinks(); //to do neighborhood searching
1102 polys = Mesh->GetPolys();
1104 for (cellId=0, polys->InitTraversal(); polys->GetNextCell(npts,pts);
1105 cellId++)
1107 if(DebugLevel>5) cout<<"->cellId="<<cellId<<endl;
1108 for (i=0; i < npts; i++)
1110 if(DebugLevel>5) cout<<"-->i="<<i<<endl;
1111 p1 = pts[i];
1112 p2 = pts[(i+1)%npts];
1114 if ( Verts[p1].edges == NULL )
1116 Verts[p1].edges = vtkIdList::New();
1117 Verts[p1].edges->Allocate(16,6);
1119 if ( Verts[p2].edges == NULL )
1121 Verts[p2].edges = vtkIdList::New();
1122 Verts[p2].edges->Allocate(16,6);
1125 Mesh->GetCellEdgeNeighbors(cellId,p1,p2,neighbors);
1126 numNei = neighbors->GetNumberOfIds();
1127 if(DebugLevel>5) cout<<"-->numNei="<<numNei<<endl;
1129 edge = VTK_SIMPLE_VERTEX;
1130 if ( numNei == 0 )
1132 edge = VTK_BOUNDARY_EDGE_VERTEX;
1135 else if ( numNei >= 2 )
1137 // check to make sure that this edge hasn't been marked already
1138 for (j=0; j < numNei; j++)
1140 if ( neighbors->GetId(j) < cellId )
1142 break;
1145 if ( j >= numNei )
1147 edge = VTK_FEATURE_EDGE_VERTEX;
1151 else if ( numNei == 1 && (nei=neighbors->GetId(0)) > cellId )
1153 vtkPolygon::ComputeNormal(inPts,npts,pts,normal);
1154 Mesh->GetCellPoints(nei,numNeiPts,neiPts);
1155 vtkPolygon::ComputeNormal(inPts,numNeiPts,neiPts,neiNormal);
1157 if ( this->FeatureEdgeSmoothing &&
1158 vtkMath::Dot(normal,neiNormal) <= CosFeatureAngle )
1160 edge = VTK_FEATURE_EDGE_VERTEX;
1163 else // a visited edge; skip rest of analysis
1165 continue;
1168 if ( edge && Verts[p1].type == VTK_SIMPLE_VERTEX )
1170 Verts[p1].edges->Reset();
1171 Verts[p1].edges->InsertNextId(p2);
1172 Verts[p1].type = edge;
1174 else if ( (edge && Verts[p1].type == VTK_BOUNDARY_EDGE_VERTEX) ||
1175 (edge && Verts[p1].type == VTK_FEATURE_EDGE_VERTEX) ||
1176 (!edge && Verts[p1].type == VTK_SIMPLE_VERTEX ) )
1178 Verts[p1].edges->InsertNextId(p2);
1179 if ( Verts[p1].type && edge == VTK_BOUNDARY_EDGE_VERTEX )
1181 Verts[p1].type = VTK_BOUNDARY_EDGE_VERTEX;
1185 if ( edge && Verts[p2].type == VTK_SIMPLE_VERTEX )
1187 Verts[p2].edges->Reset();
1188 Verts[p2].edges->InsertNextId(p1);
1189 Verts[p2].type = edge;
1191 else if ( (edge && Verts[p2].type == VTK_BOUNDARY_EDGE_VERTEX ) ||
1192 (edge && Verts[p2].type == VTK_FEATURE_EDGE_VERTEX) ||
1193 (!edge && Verts[p2].type == VTK_SIMPLE_VERTEX ) )
1195 Verts[p2].edges->InsertNextId(p1);
1196 if ( Verts[p2].type && edge == VTK_BOUNDARY_EDGE_VERTEX )
1198 Verts[p2].type = VTK_BOUNDARY_EDGE_VERTEX;
1204 inMesh->Delete();
1206 neighbors->Delete();
1207 }//if strips or polys
1209 //post-process edge vertices to make sure we can smooth them
1210 for (i=0; i<numPts; i++)
1212 if ( Verts[i].type == VTK_SIMPLE_VERTEX )
1214 numSimple++;
1217 else if ( Verts[i].type == VTK_FIXED_VERTEX )
1219 numFixed++;
1222 else if ( Verts[i].type == VTK_FEATURE_EDGE_VERTEX ||
1223 Verts[i].type == VTK_BOUNDARY_EDGE_VERTEX )
1224 { //see how many edges; if two, what the angle is
1226 if ( !this->BoundarySmoothing &&
1227 Verts[i].type == VTK_BOUNDARY_EDGE_VERTEX )
1229 if(DebugLevel>5) cout<<"Verts[i].type = VTK_FIXED_VERTEX; 4"<<endl;
1230 Verts[i].type = VTK_FIXED_VERTEX;
1231 numBEdges++;
1234 else if ( (npts = Verts[i].edges->GetNumberOfIds()) != 2 )
1236 if(DebugLevel>5) cout<<"Verts["<<i<<"].type = VTK_FIXED_VERTEX; 5"<<endl;
1237 Verts[i].type = VTK_FIXED_VERTEX;
1238 numFixed++;
1241 else //check angle between edges
1243 inPts->GetPoint(Verts[i].edges->GetId(0),x1);
1244 inPts->GetPoint(i,x2);
1245 inPts->GetPoint(Verts[i].edges->GetId(1),x3);
1247 for (k=0; k<3; k++)
1249 l1[k] = x2[k] - x1[k];
1250 l2[k] = x3[k] - x2[k];
1252 if ( vtkMath::Normalize(l1) >= 0.0 &&
1253 vtkMath::Normalize(l2) >= 0.0 &&
1254 vtkMath::Dot(l1,l2) < CosEdgeAngle)
1256 if(DebugLevel>5) cout<<"Verts["<<i<<"].type = VTK_FIXED_VERTEX; 6"<<endl;
1257 Verts[i].type = VTK_FIXED_VERTEX;
1258 numFixed++;
1260 else
1262 if ( Verts[i].type == VTK_FEATURE_EDGE_VERTEX )
1264 numFEdges++;
1266 else
1268 numBEdges++;
1271 }//if along edge
1272 }//if edge vertex
1273 }//for all points
1275 if(DebugLevel>5) {
1276 cout<<"Found\n\t" << numSimple << " simple vertices\n\t"
1277 << numFEdges << " feature edge vertices\n\t"
1278 << numBEdges << " boundary edge vertices\n\t"
1279 << numFixed << " fixed vertices\n\t"<<endl;
1280 cout<<"1:numPts="<<numPts<<endl;
1283 for (i=0; i<numPts; i++)
1285 if(DebugLevel>5) cout<<"Verts["<<i<<"].type="<<VertexType2Str(Verts[i].type)<<endl;
1286 if(Verts[i].edges != NULL && (npts = Verts[i].edges->GetNumberOfIds()) > 0)
1288 for (j=0; j<npts; j++)
1290 if(DebugLevel>5) cout<<"Verts["<<i<<"].edges->GetId("<<j<<")="<<Verts[i].edges->GetId(j)<<endl;
1291 }//for all connected points
1295 //Copy node type info from Verts
1296 EG_VTKDCN(vtkCharArray, node_type, grid, "node_type");
1297 if(DebugLevel>5) cout<<"nodes.size()="<<nodes.size()<<endl;
1298 foreach(vtkIdType node,nodes)
1300 if(DebugLevel>5) cout<<"Verts["<<node<<"].type="<<VertexType2Str(Verts[node].type)<<endl;
1301 node_type->SetValue(node,Verts[node].type);
1304 //free up connectivity storage
1305 for (int i=0; i<numPts; i++)
1307 if ( Verts[i].edges != NULL )
1309 Verts[i].edges->Delete();
1310 Verts[i].edges = NULL;
1313 delete [] Verts;
1315 return(0);
1317 //End of UpdateNodeType
1319 // DEFINITIONS:
1320 // Normal cell: nothing has changed
1321 // Dead cell: the cell does not exist anymore
1322 // Mutated cell: the cell's form has changed
1323 // Mutilated cell: the cell has less points than before
1325 vtkIdType Operation::FindSnapPoint(vtkUnstructuredGrid *src, vtkIdType DeadNode,QSet <vtkIdType> & DeadCells,QSet <vtkIdType> & MutatedCells,QSet <vtkIdType> & MutilatedCells, int& N_newpoints, int& N_newcells)
1327 getAllSurfaceCells(cells,src);
1328 getNodesFromCells(cells, nodes, src);
1329 setGrid(src);
1330 setCells(cells);
1332 UpdateNodeType();
1334 EG_VTKDCN(vtkCharArray, node_type, src, "node_type");
1335 if(node_type->GetValue(DeadNode)==VTK_FIXED_VERTEX)
1337 cout<<"Sorry, unable to remove fixed vertex."<<endl;
1338 return(-1);
1341 //src grid info
1342 int N_points=src->GetNumberOfPoints();
1343 int N_cells=src->GetNumberOfCells();
1344 N_newpoints=-1;
1345 N_newcells=0;
1347 vtkIdType SnapPoint=-1;
1349 foreach(vtkIdType PSP, n2n[DeadNode])
1351 bool IsValidSnapPoint=true;
1353 if(DebugLevel>10) cout<<"====>PSP="<<PSP<<endl;
1354 bool IsTetra=true;
1355 if(NumberOfCommonPoints(DeadNode,PSP,IsTetra)>2)//common point check
1357 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1358 IsValidSnapPoint=false;
1360 if(IsTetra)//tetra check
1362 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1363 IsValidSnapPoint=false;
1366 //count number of points and cells to remove + analyse cell transformations
1367 N_newpoints=-1;
1368 N_newcells=0;
1369 DeadCells.clear();
1370 MutatedCells.clear();
1371 MutilatedCells.clear();
1372 foreach(vtkIdType C, n2c[DeadNode])//loop through potentially dead cells
1374 //get points around cell
1375 vtkIdType N_pts, *pts;
1376 src->GetCellPoints(C, N_pts, pts);
1378 bool ContainsSnapPoint=false;
1379 bool invincible=false;
1380 for(int i=0;i<N_pts;i++)
1382 if(DebugLevel>10) cout<<"pts["<<i<<"]="<<pts[i]<<" and PSP="<<PSP<<endl;
1383 if(pts[i]==PSP) {ContainsSnapPoint=true;}
1384 if(pts[i]!=DeadNode && pts[i]!=PSP && n2c[pts[i]].size()<=1) invincible=true;
1386 if(ContainsSnapPoint)
1388 if(N_pts==3)//dead cell
1390 if(invincible)//Check that empty lines aren't left behind when a cell is killed
1392 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1393 IsValidSnapPoint=false;
1395 else
1397 DeadCells.insert(C);
1398 N_newcells-=1;
1399 if(DebugLevel>10) cout<<"cell "<<C<<" has been pwned!"<<endl;
1402 else
1404 cout<<"RED ALERT: Xenomorph detected!"<<endl;
1405 EG_BUG;
1408 else
1410 vtkIdType src_N_pts, *src_pts;
1411 src->GetCellPoints(C, src_N_pts, src_pts);
1413 if(src_N_pts!=3)
1415 cout<<"RED ALERT: Xenomorph detected!"<<endl;
1416 EG_BUG;
1419 vtkIdType OldTriangle[3];
1420 vtkIdType NewTriangle[3];
1422 for(int i=0;i<src_N_pts;i++)
1424 OldTriangle[i]=src_pts[i];
1425 NewTriangle[i]=( (src_pts[i]==DeadNode) ? PSP : src_pts[i] );
1427 vec3_t Old_N= triNormal(src, OldTriangle[0], OldTriangle[1], OldTriangle[2]);
1428 vec3_t New_N= triNormal(src, NewTriangle[0], NewTriangle[1], NewTriangle[2]);
1429 double OldArea=Old_N.abs();
1430 double NewArea=New_N.abs();
1431 double scal=Old_N*New_N;
1432 double cross=(Old_N.cross(New_N)).abs();//double-cross on Nar Shadaa B-)
1434 if(DebugLevel>10) {
1435 cout<<"OldArea="<<OldArea<<endl;
1436 cout<<"NewArea="<<NewArea<<endl;
1437 cout<<"scal="<<scal<<endl;
1438 cout<<"cross="<<cross<<endl;
1441 if(Old_N*New_N<Old_N*Old_N*1./100.)//area + inversion check
1443 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1444 IsValidSnapPoint=false;
1447 //mutated cell
1448 MutatedCells.insert(C);
1449 if(DebugLevel>10) cout<<"cell "<<C<<" has been infected!"<<endl;
1453 if(N_cells+N_newcells<=0)//survivor check
1455 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1456 IsValidSnapPoint=false;
1459 if(node_type->GetValue(DeadNode)==VTK_BOUNDARY_EDGE_VERTEX && node_type->GetValue(PSP)==VTK_SIMPLE_VERTEX)
1461 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1462 IsValidSnapPoint=false;
1465 if(node_type->GetValue(DeadNode)==VTK_BOUNDARY_EDGE_VERTEX)
1467 int BC=0;
1468 QVector <vtkIdType> Peons;
1469 getNeighbours(DeadNode, Peons, BC);
1470 if(!Peons.contains(PSP))
1472 if(DebugLevel>0) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1473 IsValidSnapPoint=false;
1477 if(node_type->GetValue(DeadNode)==VTK_FEATURE_EDGE_VERTEX && node_type->GetValue(PSP)==VTK_SIMPLE_VERTEX)
1479 if(DebugLevel>10) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1480 IsValidSnapPoint=false;
1483 if(node_type->GetValue(DeadNode)==VTK_FEATURE_EDGE_VERTEX)
1485 int BC=0;
1486 QVector <vtkIdType> Peons;
1487 getNeighbours(DeadNode, Peons, BC);
1488 if(!Peons.contains(PSP))
1490 if(DebugLevel>0) cout<<"Sorry, but you are not allowed to move point "<<DeadNode<<" to point "<<PSP<<"."<<endl;
1491 IsValidSnapPoint=false;
1495 if(IsValidSnapPoint) {SnapPoint=PSP; break;}
1496 }//end of loop through potential SnapPoints
1498 if(DebugLevel>10)
1500 cout<<"AT FINDSNAPPOINT EXIT"<<endl;
1501 cout<<"N_points="<<N_points<<endl;
1502 cout<<"N_cells="<<N_cells<<endl;
1503 cout<<"N_newpoints="<<N_newpoints<<endl;
1504 cout<<"N_newcells="<<N_newcells<<endl;
1506 return(SnapPoint);
1508 //End of FindSnapPoint
1510 bool Operation::DeletePoint_2(vtkUnstructuredGrid *src, vtkIdType DeadNode, int& N_newpoints, int& N_newcells)
1512 getAllSurfaceCells(cells,src);
1513 // getNodesFromCells(cells, nodes, src);
1514 setGrid(src);
1515 setCells(cells);
1516 UpdateNodeType();
1518 //src grid info
1519 int N_points=src->GetNumberOfPoints();
1520 int N_cells=src->GetNumberOfCells();
1521 N_newpoints=-1;
1522 N_newcells=0;
1524 if(DeadNode<0 || DeadNode>=N_points)
1526 cout<<"Warning: Point out of range: DeadNode="<<DeadNode<<" N_points="<<N_points<<endl;
1527 return(false);
1530 QSet <vtkIdType> DeadCells;
1531 QSet <vtkIdType> MutatedCells;
1532 QSet <vtkIdType> MutilatedCells;
1534 if(DebugLevel>10) {
1535 cout<<"BEFORE FINDSNAPPOINT"<<endl;
1536 cout<<"N_points="<<N_points<<endl;
1537 cout<<"N_cells="<<N_cells<<endl;
1538 cout<<"N_newpoints="<<N_newpoints<<endl;
1539 cout<<"N_newcells="<<N_newcells<<endl;
1541 vtkIdType SnapPoint=FindSnapPoint(src,DeadNode,DeadCells,MutatedCells,MutilatedCells, N_newpoints, N_newcells);
1543 if(DebugLevel>0) cout<<"===>DeadNode="<<DeadNode<<" moving to SNAPPOINT="<<SnapPoint<<" DebugLevel="<<DebugLevel<<endl;
1544 if(SnapPoint<0) {cout<<"Sorry no possible SnapPoint found."<<endl; return(false);}
1546 //allocate
1547 if(DebugLevel>10) {
1548 cout<<"BEFORE ALLOCATION"<<endl;
1549 cout<<"N_points="<<N_points<<endl;
1550 cout<<"N_cells="<<N_cells<<endl;
1551 cout<<"N_newpoints="<<N_newpoints<<endl;
1552 cout<<"N_newcells="<<N_newcells<<endl;
1554 N_points=src->GetNumberOfPoints();
1555 N_cells=src->GetNumberOfCells();
1557 if(DebugLevel>47) {
1558 cout<<"N_points="<<N_points<<endl;
1559 cout<<"N_cells="<<N_cells<<endl;
1560 cout<<"N_newpoints="<<N_newpoints<<endl;
1561 cout<<"N_newcells="<<N_newcells<<endl;
1563 EG_VTKSP(vtkUnstructuredGrid,dst);
1564 allocateGrid(dst,N_cells+N_newcells,N_points+N_newpoints);
1566 //vector used to redefine the new point IDs
1567 QVector <vtkIdType> OffSet(N_points);
1569 //copy undead points
1570 vtkIdType dst_id_node=0;
1571 for (vtkIdType src_id_node = 0; src_id_node < N_points; src_id_node++) {//loop through src points
1572 if(src_id_node!=DeadNode)//if the node isn't dead, copy it
1574 vec3_t x;
1575 src->GetPoints()->GetPoint(src_id_node, x.data());
1576 dst->GetPoints()->SetPoint(dst_id_node, x.data());
1577 copyNodeData(src, src_id_node, dst, dst_id_node);
1578 OffSet[src_id_node]=src_id_node-dst_id_node;
1579 dst_id_node++;
1581 else
1583 if(DebugLevel>0) cout<<"src_id_node="<<src_id_node<<" dst_id_node="<<dst_id_node<<endl;
1586 if(DebugLevel>10) {
1587 cout<<"DeadCells="<<DeadCells<<endl;
1588 cout<<"MutatedCells="<<MutatedCells<<endl;
1589 cout<<"MutilatedCells="<<MutilatedCells<<endl;
1591 //Copy undead cells
1592 for (vtkIdType id_cell = 0; id_cell < src->GetNumberOfCells(); ++id_cell) {//loop through src cells
1593 if(!DeadCells.contains(id_cell))//if the cell isn't dead
1595 vtkIdType src_N_pts, *src_pts;
1596 vtkIdType dst_N_pts, *dst_pts;
1597 src->GetCellPoints(id_cell, src_N_pts, src_pts);
1599 vtkIdType type_cell = src->GetCellType(id_cell);
1600 if(DebugLevel>10) cout<<"-->id_cell="<<id_cell<<endl;
1601 if(DebugLevel>10) for(int i=0;i<src_N_pts;i++) cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
1602 // src->GetCellPoints(id_cell, dst_N_pts, dst_pts);
1603 dst_N_pts=src_N_pts;
1604 dst_pts=new vtkIdType[dst_N_pts];
1605 if(MutatedCells.contains(id_cell))//mutated cell
1607 if(DebugLevel>10) cout<<"processing mutated cell "<<id_cell<<endl;
1608 for(int i=0;i<src_N_pts;i++)
1610 if(src_pts[i]==DeadNode) {
1611 if(DebugLevel>10) {
1612 cout<<"SnapPoint="<<SnapPoint<<endl;
1613 cout<<"OffSet[SnapPoint]="<<OffSet[SnapPoint]<<endl;
1614 cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
1616 dst_pts[i]=SnapPoint-OffSet[SnapPoint];
1618 else dst_pts[i]=src_pts[i]-OffSet[src_pts[i]];
1620 if(DebugLevel>10) cout<<"--->dst_pts:"<<endl;
1621 if(DebugLevel>10) for(int i=0;i<dst_N_pts;i++) cout<<"dst_pts["<<i<<"]="<<dst_pts[i]<<endl;
1624 else if(MutilatedCells.contains(id_cell))//mutilated cell
1626 if(DebugLevel>10) cout<<"processing mutilated cell "<<id_cell<<endl;
1628 if(type_cell==VTK_QUAD) {
1629 type_cell=VTK_TRIANGLE;
1630 dst_N_pts-=1;
1632 else {cout<<"FATAL ERROR: Unknown mutilated cell detected! It is not a quad! Potential xenomorph infestation!"<<endl;EG_BUG;}
1633 //merge points
1634 int j=0;
1635 for(int i=0;i<src_N_pts;i++)
1637 if(src_pts[i]==SnapPoint) { dst_pts[j]=SnapPoint-OffSet[SnapPoint];j++; }//SnapPoint
1638 else if(src_pts[i]!=DeadNode) { dst_pts[j]=src_pts[i]-OffSet[src_pts[i]];j++; }//pre-snap/dead + post-snap/dead
1639 //do nothing in case of DeadNode
1642 else//normal cell
1644 if(DebugLevel>10) cout<<"processing normal cell "<<id_cell<<endl;
1645 for(int i=0;i<src_N_pts;i++)
1647 dst_pts[i]=src_pts[i]-OffSet[src_pts[i]];
1650 //copy the cell
1651 vtkIdType id_new_cell = dst->InsertNextCell(type_cell, dst_N_pts, dst_pts);
1652 copyCellData(src, id_cell, dst, id_new_cell);
1653 if(DebugLevel>10) {
1654 cout<<"===Copying cell "<<id_cell<<" to "<<id_new_cell<<"==="<<endl;
1655 cout<<"src_pts:"<<endl;
1656 for(int i=0;i<src_N_pts;i++) cout<<"src_pts["<<i<<"]="<<src_pts[i]<<endl;
1657 cout<<"dst_pts:"<<endl;
1658 for(int i=0;i<dst_N_pts;i++) cout<<"dst_pts["<<i<<"]="<<dst_pts[i]<<endl;
1659 cout<<"OffSet="<<OffSet<<endl;
1660 cout<<"===Copying cell end==="<<endl;
1662 delete dst_pts;
1665 // cout_grid(cout,dst,true,true,true,true);
1666 makeCopy(dst, src);
1667 return(true);
1669 //End of DeletePoint_2
1671 void Operation::TxtSave(QString a_filename)
1673 cout << a_filename.toAscii().data() << endl;
1674 ofstream file;
1675 file.open(a_filename.toAscii().data());
1676 cout_grid(file,grid,true,true,true,true);
1677 file.close();
1680 void Operation::DualSave(QString a_filename)
1682 TxtSave(a_filename+".txt");
1683 GuiMainWindow::pointer()->QuickSave(a_filename+".vtu");