MorphoGraphX  2.0-1-227
MeshProcessStructure.hpp
Go to the documentation of this file.
1 //
2 // This file is part of MorphoGraphX - http://www.MorphoGraphX.org
3 // Copyright (C) 2012-2016 Richard S. Smith and collaborators.
4 //
5 // If you use MorphoGraphX in your work, please cite:
6 // http://dx.doi.org/10.7554/eLife.05864
7 //
8 // MorphoGraphX is free software, and is licensed under under the terms of the
9 // GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
10 //
11 #ifndef MESH_PROCESS_STRUCTURE_HPP
12 #define MESH_PROCESS_STRUCTURE_HPP
13 
14 #include <Process.hpp>
15 
16 #include <Misc.hpp>
17 #include <Subdivide.hpp>
18 
19 namespace mgx
20 {
23 
30  class mgxBase_EXPORT TransformMesh : public Process
31  {
32  public:
33  TransformMesh(const Process& process) : Process(process)
34  {
35  setName("Mesh/Structure/Transform Mesh");
36  setDesc("Apply an affine transformation to all vertices of a mesh");
37  setIcon(QIcon(":/images/Resize.png"));
38 
39  addParm("translation (µm)","Translation in micrometers. Enter x y z separated by spaces","0.0 0.0 0.0");
40  addParm("rotation axis","Vector representing the axis of rotation. Enter x y z separated by spaces","0.0 0.0 1.0");
41  addParm("angle (degree)","Angle of rotation in degrees","0.0");
42  addParm("scale","Global scaling factor","1.0");
43  }
44 
45  bool run()
46  {
47  if(!checkState().mesh(MESH_NON_EMPTY))
48  return false;
49  Point3f trans, rot;
50  {
51  QString txt = parm("translation (µm)");
52  QTextStream ts(&txt);
53  ts >> trans;
54  }
55  {
56  QString txt = parm("rotation axis");
57  QTextStream ts(&txt);
58  ts >> rot;
59  }
60  bool ok;
61  float angle = parm("angle (degree)").toFloat(&ok) * M_PI / 180.f;
62  if(!ok)
63  return setErrorMessage("Error, the 'angle' parameter must be a number");
64  float scale = parm("scale").toFloat(&ok);
65  if(!ok)
66  return setErrorMessage("Error, the 'scale' parameter must be a number");
67  return run(currentMesh(), trans, rot, angle, scale);
68  }
69 
70  bool run(Mesh* mesh, Point3f translation, Point3f rotation_axis, float rotation,
71  float scale);
72 
73  };
74 
80  class mgxBase_EXPORT ReverseMesh : public Process
81  {
82  public:
83  ReverseMesh(const Process& process) : Process(process)
84  {
85  setName("Mesh/Structure/Reverse Mesh");
86  setDesc("Reverse orientation of the mesh");
87  setIcon(QIcon(":/images/Invert.png"));
88  }
89 
90  bool run()
91  {
92  if(!checkState().mesh(MESH_NON_EMPTY))
93  return false;
94  return run(currentMesh());
95  }
96  bool run(Mesh* mesh);
97 
98  };
99 
105  class mgxBase_EXPORT SmoothMesh : public Process
106  {
107  public:
108  SmoothMesh(const Process& process) : Process(process)
109  {
110  setName("Mesh/Structure/Smooth Mesh");
111  setDesc("Average each vertex position based on its neighbors.");
112  setIcon(QIcon(":/images/SmoothMesh.png"));
113 
114  addParm("Passes","Passes","1");
115  addParm("Walls Only","Walls Only","No",booleanChoice());
116  }
117 
118  bool run()
119  {
120  if(!checkState().mesh(MESH_NON_EMPTY))
121  return false;
122  return run(currentMesh(), parm("Passes").toUInt(), stringToBool(parm("Walls Only")));
123  }
124 
125  bool run(Mesh* mesh, uint passes, bool wallsOnly = false);
126 
127  };
128 
134  class mgxBase_EXPORT ShrinkMesh : public Process
135  {
136  public:
137  ShrinkMesh(const Process& process) : Process(process)
138  {
139  setName("Mesh/Structure/Shrink Mesh");
140  setDesc("Displace each vertex towards the mesh center, perpendicular to the surface.");
141  setIcon(QIcon(":/images/ShrinkMesh.png"));
142 
143  addParm("Distance(µm)","Vertex displacement. If negtive, the mesh will expand.","1.0");
144  }
145 
146  bool run()
147  {
148  if(!checkState().mesh(MESH_NON_EMPTY))
149  return false;
150  return run(currentMesh(), parm("Distance(µm)").toFloat());
151  }
152 
153  bool run(Mesh* mesh, float distance);
154 
155  };
156 
162  class mgxBase_EXPORT LoopSubdivisionMesh : public Process
163  {
164  public:
165  LoopSubdivisionMesh(const Process& process) : Process(process)
166  {
167  setName("Mesh/Structure/Loop Subdivision");
168  setDesc("Subdivide the mesh uniformly using Loop subdivision.");
169  setIcon(QIcon(":/images/SubdivideTri.png"));
170  }
171 
172  bool run()
173  {
174  if(!checkState().mesh(MESH_NON_EMPTY))
175  return false;
176  return run(currentMesh());
177  }
178 
179  bool run(Mesh* mesh);
180 
181  };
182 
188  class mgxBase_EXPORT SubdivideMesh : public Process
189  {
190  public:
191  SubdivideMesh(const Process& process) : Process(process)
192  {
193  setName("Mesh/Structure/Subdivide");
194  setDesc("Subdivide the mesh unifromly");
195  setIcon(QIcon(":/images/SubdivideTri.png"));
196  }
197 
198  bool run()
199  {
200  if(!checkState().mesh(MESH_NON_EMPTY))
201  return false;
202  return run(currentMesh());
203  }
204 
205  bool run(Mesh* mesh);
206  };
207 
213  class mgxBase_EXPORT AdaptiveSubdivideBorderMesh : public Process
214  {
215  public:
216  AdaptiveSubdivideBorderMesh(const Process& process) : Process(process)
217  {
218  setName("Mesh/Structure/Subdivide Adaptive Near Borders");
219  setDesc("Subdivide triangles around cell borders");
220  setIcon(QIcon(":/images/SubdivideTriAdapt.png"));
221 
222  addParm("Max Area(µm²)","Area threshold (in square microns) for subdivision, triangles smaller than this won't be subdivided","0.1");
223  addParm("Border Dist(µm)","Distance (in microns) from cell borders that triangles will be subdivided","1.0");
224  }
225 
226  bool run()
227  {
228  if(!checkState().mesh(MESH_NON_EMPTY))
229  return false;
230  return run(currentMesh(), parm("Max Area(µm²)").toFloat(), parm("Border Dist(µm)").toFloat());
231  }
232 
233  bool run(Mesh* mesh, float cellMaxArea, float borderDist);
234 
235  };
236 
244  class mgxBase_EXPORT AdaptiveSubdivideSignalMesh : public Process
245  {
246  public:
247  AdaptiveSubdivideSignalMesh(const Process& process) : Process(process)
248  {
249  setName("Mesh/Structure/Subdivide Adaptive by Signal");
250  setDesc("Subdivide triangles depending on mesh signal. Triangle size \N"
251  "is determined by a high and low area, which is interpolated \N"
252  "based on the minimum and maximum signals");
253  setIcon(QIcon(":/images/SubdivideTriAdapt.png"));
254 
255  addParm("Low Max Area(µm²)","Maximum area (square microns) for low instentity voxels","1.0");
256  addParm("High Max Area(µm²)","Maximum area (square microns) for high instentity voxels","0.1");
257  }
258 
259  bool run()
260  {
261  if(!checkState().mesh(MESH_NON_EMPTY))
262  return false;
263  return run(currentMesh(), parm("Low Max Area(µm²)").toFloat(), parm("High Max Area(µm²)").toFloat());
264  }
265 
266  bool run(Mesh* mesh, float cellMaxAreaLow, float cellMaxAreaHigh);
267 
268  };
269 
275  class mgxBase_EXPORT SubdivideBisectMesh : public Process
276  {
277  public:
278  SubdivideBisectMesh(const Process& process) : Process(process)
279  {
280  setName("Mesh/Structure/Subdivide with Bisection MGX3D");
281  setDesc("Subdivide triangles area with bisection");
282  setIcon(QIcon(":/images/SubdivideTriAdapt.png"));
283 
284  addParm("Max Area(µm²)","Max Area(µm²)","1.0");
285  }
286 
287  bool run()
288  {
289  if(!checkState().mesh(MESH_NON_EMPTY))
290  return false;
291  return run(currentMesh(), parm("Max Area(µm²)").toFloat());
292  }
293 
294  bool run(Mesh* mesh, float cellMaxArea);
295 
296  };
297 
303  class mgxBase_EXPORT SubdivideBisectMesh3D : public Process
304  {
305  public:
306  SubdivideBisectMesh3D(const Process& process) : Process(process)
307  {
308  setName("Mesh/Structure/Subdivide with Bisection MGX3D");
309  setDesc("Subdivide triangles area with bisection");
310  setIcon(QIcon(":/images/SubdivideTriAdapt.png"));
311 
312  addParm("Max Area(µm²)","Max Area(µm²)","1.0");
313  }
314 
315  bool run()
316  {
317  if(!checkState().mesh(MESH_NON_EMPTY))
318  return false;
319  return run(currentMesh(), parm("Max Area(µm²)").toFloat());
320  }
321 
322  bool run(Mesh* mesh, float cellMaxArea);
323 
324  };
325 
332  class mgxBase_EXPORT ScaleMesh : public Process
333  {
334  public:
335  ScaleMesh(const Process& process) : Process(process)
336  {
337  setName("Mesh/Structure/Scale Mesh");
338  setDesc("Scale Mesh, or a selected part of it. \n"
339  "It is possible to specify a negative number, in which case the dimension will be mirrored. \N"
340  "If either 1 or 3 axis are mirrored, then the whole mesh needs to be scaled, as these triangles will change orientation");
341  setIcon(QIcon(":/images/Scale.png"));
342 
343  addParm("X Scale","X Scale","1.0");
344  addParm("Y Scale","Y Scale","1.0");
345  addParm("Z Scale","Z Scale","1.0");
346  }
347 
348  bool run()
349  {
350  if(!checkState().mesh(MESH_NON_EMPTY))
351  return false;
352  return run(currentMesh(), parm("X Scale").toFloat(), parm("Y Scale").toFloat(), parm("Z Scale").toFloat());
353  }
354 
355  bool run(Mesh* mesh, float scaleX, float scaleY, float scaleZ);
356 
357  };
358 
364  class mgxBase_EXPORT MeshDeleteValence : public Process
365  {
366  public:
367  MeshDeleteValence(const Process& process) : Process(process)
368  {
369  setName("Mesh/Structure/Delete Mesh Vertices by Valence");
370  setDesc("Delete mesh vertices that have valence within the specified range");
371  setIcon(QIcon(":/images/DeleteValence"));
372 
373  addParm("Start Valence","Start Valence","0");
374  addParm("End Valence","End Valence","2");
375  }
376 
377  bool run()
378  {
379  if(!checkState().mesh(MESH_NON_EMPTY))
380  return false;
381  return run(currentMesh(), parm("Start Valence").toInt(), parm("End Valence").toInt());
382  }
383 
384  bool run(Mesh* mesh, int startValence, int endValence);
385 
386  };
387 
393  class mgxBase_EXPORT MergeVertices : public Process
394  {
395  public:
396  MergeVertices(const Process& process) : Process(process)
397  {
398  setName("Mesh/Structure/Merge Vertices");
399  setDesc("Merge selected vertices into one.");
400  setIcon(QIcon(":/images/MergeVertices"));
401  }
402 
403  bool run()
404  {
405  if(!checkState().mesh(MESH_NON_EMPTY))
406  return false;
407  return run(currentMesh());
408  }
409 
410  bool run(Mesh* mesh);
411 
412  };
413 
419  class mgxBase_EXPORT SplitEdges : public Process
420  {
421  public:
422  SplitEdges(const Process& process) : Process(process)
423  {
424  setName("Mesh/Structure/Split Edges");
425  setDesc("Split edges by inserting a new vertex in the middle.");
426  setIcon(QIcon(":/images/SplitEdge"));
427 
428  addParm("Max Dist","Maximum distance between vertices (um), 0 divides once","1.0");
429  }
430 
431  bool run()
432  {
433  if(!checkState().mesh(MESH_NON_EMPTY))
434  return false;
435 
436  Mesh *mesh = currentMesh();
437  vvGraph &S = mesh->graph();
438 
439  bool result = run(mesh, parm("Max Dist").toDouble());
440  SETSTATUS("Mesh " << mesh->userId() << " - Split edges, total vertices:" << S.size());
441  return result;
442  }
443 
444  bool run(Mesh* mesh, double maxDist, Subdivide *sDiv = 0);
445 
446  };
447 
453  class mgxBase_EXPORT DeleteEdge : public Process
454  {
455  public:
456  DeleteEdge(const Process& process) : Process(process)
457  {
458  setName("Mesh/Structure/Delete Edge");
459  setDesc("Delete edge between 2 selected vertices.");
460  setIcon(QIcon(":/images/DeleteLabel.png"));
461  }
462 
463  bool run()
464  {
465  if(!checkState().mesh(MESH_NON_EMPTY))
466  return false;
467  return run(currentMesh());
468  }
469 
470  bool run(Mesh* mesh);
471 
472  };
473 
479  class mgxBase_EXPORT MeshDeleteSelection : public Process
480  {
481  public:
482  MeshDeleteSelection(const Process& process) : Process(process)
483  {
484  setName("Mesh/Structure/Delete Selection");
485  setDesc("Delete vertices selected in the current mesh, preserving cells.");
486  setIcon(QIcon(":/images/DeleteLabel.png"));
487  }
488 
489  bool run()
490  {
491  if(!checkState().mesh(MESH_NON_EMPTY | MESH_SHOW_MESH))
492  return false;
493  return run(currentMesh());
494  }
495 
496  bool run(Mesh* m);
497 
498  };
499 
505  class mgxBase_EXPORT MeshKeepVertices : public Process
506  {
507  public:
508  MeshKeepVertices(const Process& process) : Process(process)
509  {
510  setName("Mesh/Structure/Keep Vertices");
511  setDesc("Mark vertices so that they can survive as lines and points. Also prevents labels changing.");
512  setIcon(QIcon(":/images/KeepVertices.png"));
513 
514  addParm("Keep","Keep","Yes",booleanChoice());
515  }
516 
517  bool run()
518  {
519  if(!checkState().mesh(MESH_NON_EMPTY | MESH_SHOW_MESH))
520  return false;
521  bool keep = stringToBool(parm("Keep"));
522  return run(currentMesh(), keep);
523  }
524 
525  bool run(Mesh* m, bool keep);
526 
527  };
529 }
530 #endif
mgx::SplitEdges::SplitEdges
SplitEdges(const Process &process)
Definition: MeshProcessStructure.hpp:422
mgx::MergeVertices
Definition: MeshProcessStructure.hpp:393
mgx::ReverseMesh
Definition: MeshProcessStructure.hpp:80
mgx::uint
unsigned int uint
Definition: Geometry.hpp:41
mgx::DeleteEdge::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:463
Process.hpp
mgx::MergeVertices::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:403
mgx::MeshDeleteValence::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:377
mgx::TransformMesh::TransformMesh
TransformMesh(const Process &process)
Definition: MeshProcessStructure.hpp:33
mgx::AdaptiveSubdivideSignalMesh
Definition: MeshProcessStructure.hpp:244
mgx::ScaleMesh
Definition: MeshProcessStructure.hpp:332
mgx::MeshKeepVertices::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:517
mgx::SubdivideBisectMesh3D::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:315
mgx::MeshDeleteValence
Definition: MeshProcessStructure.hpp:364
mgx::SplitEdges::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:431
mgx::SubdivideMesh::SubdivideMesh
SubdivideMesh(const Process &process)
Definition: MeshProcessStructure.hpp:191
mgx::ShrinkMesh
Definition: MeshProcessStructure.hpp:134
mgx::TransformMesh
Definition: MeshProcessStructure.hpp:30
mgx::SubdivideBisectMesh3D
Definition: MeshProcessStructure.hpp:303
mgx::Mesh::userId
int userId() const
Id as seen by the user.
Definition: Mesh.hpp:114
mgx::ReverseMesh::ReverseMesh
ReverseMesh(const Process &process)
Definition: MeshProcessStructure.hpp:83
mgx::AdaptiveSubdivideBorderMesh
Definition: MeshProcessStructure.hpp:213
mgx::LoopSubdivisionMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:172
mgx
Distributed matrix library.
Definition: Assert.hpp:26
mgx::MeshKeepVertices::MeshKeepVertices
MeshKeepVertices(const Process &process)
Definition: MeshProcessStructure.hpp:508
mgx::SmoothMesh
Definition: MeshProcessStructure.hpp:105
mgx::SubdivideBisectMesh::SubdivideBisectMesh
SubdivideBisectMesh(const Process &process)
Definition: MeshProcessStructure.hpp:278
mgx::ScaleMesh::ScaleMesh
ScaleMesh(const Process &process)
Definition: MeshProcessStructure.hpp:335
mgx::MeshKeepVertices
Definition: MeshProcessStructure.hpp:505
Subdivide.hpp
mgx::SmoothMesh::SmoothMesh
SmoothMesh(const Process &process)
Definition: MeshProcessStructure.hpp:108
mgx::SubdivideBisectMesh
Definition: MeshProcessStructure.hpp:275
mgx::LoopSubdivisionMesh::LoopSubdivisionMesh
LoopSubdivisionMesh(const Process &process)
Definition: MeshProcessStructure.hpp:165
mgx::MergeVertices::MergeVertices
MergeVertices(const Process &process)
Definition: MeshProcessStructure.hpp:396
mgx::Process
Definition: Process.hpp:219
mgx::AdaptiveSubdivideBorderMesh::AdaptiveSubdivideBorderMesh
AdaptiveSubdivideBorderMesh(const Process &process)
Definition: MeshProcessStructure.hpp:216
mgx::stringToBool
mgx_EXPORT bool stringToBool(const QString &string)
Helper function converting a string into a boolean.
mgx::MeshDeleteSelection::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:489
mgx::SplitEdges
Definition: MeshProcessStructure.hpp:419
mgx::VVGraph::size
size_type size() const
Return the number of vertexes on the graph.
Definition: VVGraph.hpp:552
mgx::SubdivideMesh
Definition: MeshProcessStructure.hpp:188
mgx::ScaleMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:348
mgx::DeleteEdge
Definition: MeshProcessStructure.hpp:453
SETSTATUS
#define SETSTATUS(msg)
Definition: Information.hpp:25
mgx::AdaptiveSubdivideSignalMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:259
mgx::Mesh
Definition: Mesh.hpp:54
mgx::ShrinkMesh::ShrinkMesh
ShrinkMesh(const Process &process)
Definition: MeshProcessStructure.hpp:137
mgx::MeshDeleteValence::MeshDeleteValence
MeshDeleteValence(const Process &process)
Definition: MeshProcessStructure.hpp:367
mgx::SmoothMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:118
Misc.hpp
mgx::Mesh::graph
vvGraph & graph()
Get the VV graph of the mesh.
Definition: Mesh.hpp:355
mgx::Vector< 3, float >
mgx::DeleteEdge::DeleteEdge
DeleteEdge(const Process &process)
Definition: MeshProcessStructure.hpp:456
mgx::LoopSubdivisionMesh
Definition: MeshProcessStructure.hpp:162
mgx::TransformMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:45
mgx::ReverseMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:90
mgx::SubdivideBisectMesh3D::SubdivideBisectMesh3D
SubdivideBisectMesh3D(const Process &process)
Definition: MeshProcessStructure.hpp:306
mgx::MeshDeleteSelection
Definition: MeshProcessStructure.hpp:479
mgx::AdaptiveSubdivideBorderMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:226
mgx::VVGraph< VertexData, EdgeData >
mgx::SubdivideMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:198
mgx::MeshDeleteSelection::MeshDeleteSelection
MeshDeleteSelection(const Process &process)
Definition: MeshProcessStructure.hpp:482
mgx::Subdivide
Definition: Subdivide.hpp:25
mgx::SubdivideBisectMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:287
mgx::ShrinkMesh::run
bool run()
Runs the process.
Definition: MeshProcessStructure.hpp:146
mgx::AdaptiveSubdivideSignalMesh::AdaptiveSubdivideSignalMesh
AdaptiveSubdivideSignalMesh(const Process &process)
Definition: MeshProcessStructure.hpp:247