11 #ifndef MESH_PROCESS_STRUCTURE_HPP
12 #define MESH_PROCESS_STRUCTURE_HPP
35 setName(
"Mesh/Structure/Transform Mesh");
36 setDesc(
"Apply an affine transformation to all vertices of a mesh");
37 setIcon(QIcon(
":/images/Resize.png"));
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");
47 if(!checkState().mesh(MESH_NON_EMPTY))
51 QString txt = parm(
"translation (µm)");
56 QString txt = parm(
"rotation axis");
61 float angle = parm(
"angle (degree)").toFloat(&ok) * M_PI / 180.f;
63 return setErrorMessage(
"Error, the 'angle' parameter must be a number");
64 float scale = parm(
"scale").toFloat(&ok);
66 return setErrorMessage(
"Error, the 'scale' parameter must be a number");
67 return run(currentMesh(), trans, rot, angle, scale);
85 setName(
"Mesh/Structure/Reverse Mesh");
86 setDesc(
"Reverse orientation of the mesh");
87 setIcon(QIcon(
":/images/Invert.png"));
92 if(!checkState().mesh(MESH_NON_EMPTY))
94 return run(currentMesh());
110 setName(
"Mesh/Structure/Smooth Mesh");
111 setDesc(
"Average each vertex position based on its neighbors.");
112 setIcon(QIcon(
":/images/SmoothMesh.png"));
114 addParm(
"Passes",
"Passes",
"1");
115 addParm(
"Walls Only",
"Walls Only",
"No",booleanChoice());
120 if(!checkState().mesh(MESH_NON_EMPTY))
122 return run(currentMesh(), parm(
"Passes").toUInt(),
stringToBool(parm(
"Walls Only")));
125 bool run(
Mesh* mesh,
uint passes,
bool wallsOnly =
false);
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"));
143 addParm(
"Distance(µm)",
"Vertex displacement. If negtive, the mesh will expand.",
"1.0");
148 if(!checkState().mesh(MESH_NON_EMPTY))
150 return run(currentMesh(), parm(
"Distance(µm)").toFloat());
153 bool run(
Mesh* mesh,
float distance);
167 setName(
"Mesh/Structure/Loop Subdivision");
168 setDesc(
"Subdivide the mesh uniformly using Loop subdivision.");
169 setIcon(QIcon(
":/images/SubdivideTri.png"));
174 if(!checkState().mesh(MESH_NON_EMPTY))
176 return run(currentMesh());
179 bool run(
Mesh* mesh);
193 setName(
"Mesh/Structure/Subdivide");
194 setDesc(
"Subdivide the mesh unifromly");
195 setIcon(QIcon(
":/images/SubdivideTri.png"));
200 if(!checkState().mesh(MESH_NON_EMPTY))
202 return run(currentMesh());
205 bool run(
Mesh* mesh);
218 setName(
"Mesh/Structure/Subdivide Adaptive Near Borders");
219 setDesc(
"Subdivide triangles around cell borders");
220 setIcon(QIcon(
":/images/SubdivideTriAdapt.png"));
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");
228 if(!checkState().mesh(MESH_NON_EMPTY))
230 return run(currentMesh(), parm(
"Max Area(µm²)").toFloat(), parm(
"Border Dist(µm)").toFloat());
233 bool run(
Mesh* mesh,
float cellMaxArea,
float borderDist);
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"));
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");
261 if(!checkState().mesh(MESH_NON_EMPTY))
263 return run(currentMesh(), parm(
"Low Max Area(µm²)").toFloat(), parm(
"High Max Area(µm²)").toFloat());
266 bool run(
Mesh* mesh,
float cellMaxAreaLow,
float cellMaxAreaHigh);
280 setName(
"Mesh/Structure/Subdivide with Bisection MGX3D");
281 setDesc(
"Subdivide triangles area with bisection");
282 setIcon(QIcon(
":/images/SubdivideTriAdapt.png"));
284 addParm(
"Max Area(µm²)",
"Max Area(µm²)",
"1.0");
289 if(!checkState().mesh(MESH_NON_EMPTY))
291 return run(currentMesh(), parm(
"Max Area(µm²)").toFloat());
294 bool run(
Mesh* mesh,
float cellMaxArea);
308 setName(
"Mesh/Structure/Subdivide with Bisection MGX3D");
309 setDesc(
"Subdivide triangles area with bisection");
310 setIcon(QIcon(
":/images/SubdivideTriAdapt.png"));
312 addParm(
"Max Area(µm²)",
"Max Area(µm²)",
"1.0");
317 if(!checkState().mesh(MESH_NON_EMPTY))
319 return run(currentMesh(), parm(
"Max Area(µm²)").toFloat());
322 bool run(
Mesh* mesh,
float cellMaxArea);
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"));
343 addParm(
"X Scale",
"X Scale",
"1.0");
344 addParm(
"Y Scale",
"Y Scale",
"1.0");
345 addParm(
"Z Scale",
"Z Scale",
"1.0");
350 if(!checkState().mesh(MESH_NON_EMPTY))
352 return run(currentMesh(), parm(
"X Scale").toFloat(), parm(
"Y Scale").toFloat(), parm(
"Z Scale").toFloat());
355 bool run(
Mesh* mesh,
float scaleX,
float scaleY,
float scaleZ);
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"));
373 addParm(
"Start Valence",
"Start Valence",
"0");
374 addParm(
"End Valence",
"End Valence",
"2");
379 if(!checkState().mesh(MESH_NON_EMPTY))
381 return run(currentMesh(), parm(
"Start Valence").toInt(), parm(
"End Valence").toInt());
384 bool run(
Mesh* mesh,
int startValence,
int endValence);
398 setName(
"Mesh/Structure/Merge Vertices");
399 setDesc(
"Merge selected vertices into one.");
400 setIcon(QIcon(
":/images/MergeVertices"));
405 if(!checkState().mesh(MESH_NON_EMPTY))
407 return run(currentMesh());
410 bool run(
Mesh* mesh);
424 setName(
"Mesh/Structure/Split Edges");
425 setDesc(
"Split edges by inserting a new vertex in the middle.");
426 setIcon(QIcon(
":/images/SplitEdge"));
428 addParm(
"Max Dist",
"Maximum distance between vertices (um), 0 divides once",
"1.0");
433 if(!checkState().mesh(MESH_NON_EMPTY))
436 Mesh *mesh = currentMesh();
439 bool result = run(mesh, parm(
"Max Dist").toDouble());
458 setName(
"Mesh/Structure/Delete Edge");
459 setDesc(
"Delete edge between 2 selected vertices.");
460 setIcon(QIcon(
":/images/DeleteLabel.png"));
465 if(!checkState().mesh(MESH_NON_EMPTY))
467 return run(currentMesh());
470 bool run(
Mesh* mesh);
484 setName(
"Mesh/Structure/Delete Selection");
485 setDesc(
"Delete vertices selected in the current mesh, preserving cells.");
486 setIcon(QIcon(
":/images/DeleteLabel.png"));
491 if(!checkState().mesh(MESH_NON_EMPTY | MESH_SHOW_MESH))
493 return run(currentMesh());
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"));
514 addParm(
"Keep",
"Keep",
"Yes",booleanChoice());
519 if(!checkState().mesh(MESH_NON_EMPTY | MESH_SHOW_MESH))
522 return run(currentMesh(), keep);
525 bool run(
Mesh* m,
bool keep);