Developer Documentation

EdgeFunctions.cc
1
2 /*===========================================================================*\
3 * *
4 * OpenFlipper *
5 * Copyright (c) 2001-2015, RWTH-Aachen University *
6 * Department of Computer Graphics and Multimedia *
7 * All rights reserved. *
8 * www.openflipper.org *
9 * *
10 *---------------------------------------------------------------------------*
11 * This file is part of OpenFlipper. *
12 *---------------------------------------------------------------------------*
13 * *
14 * Redistribution and use in source and binary forms, with or without *
15 * modification, are permitted provided that the following conditions *
16 * are met: *
17 * *
18 * 1. Redistributions of source code must retain the above copyright notice, *
19 * this list of conditions and the following disclaimer. *
20 * *
21 * 2. Redistributions in binary form must reproduce the above copyright *
22 * notice, this list of conditions and the following disclaimer in the *
23 * documentation and/or other materials provided with the distribution. *
24 * *
25 * 3. Neither the name of the copyright holder nor the names of its *
26 * contributors may be used to endorse or promote products derived from *
27 * this software without specific prior written permission. *
28 * *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
32 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
33 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
35 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
36 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
40 * *
41 \*===========================================================================*/
42
43 #include "MeshRepairPlugin.hh"
44 #include <MeshTools/MeshSelectionT.hh>
45
46 //-----------------------------------------------------------------------------
47
48 void MeshRepairPlugin::selectEdgesShorterThan(int _objectId,double _length) {
49 selectionEdgeLength(_objectId,_length,false);
50
51 emit scriptInfo( "selectEdgesShorterThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
52 }
53
54 //-----------------------------------------------------------------------------
55
56 void MeshRepairPlugin::selectEdgesLongerThan(int _objectId,double _length) {
57 selectionEdgeLength(_objectId,_length,true);
58
59 emit scriptInfo( "selectEdgesLongerThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
60 }
61
62 //-----------------------------------------------------------------------------
63
64
65 void MeshRepairPlugin::selectionEdgeLength(int _objectId, double _length, bool _larger) {
66
67 // get the target mesh
68 TriMesh* triMesh = 0;
69
70 PluginFunctions::getMesh(_objectId,triMesh);
71
72 if ( triMesh ) {
73 TriMesh::EdgeIter e_it, e_end=triMesh->edges_end();
74
75 // Clear current edge selection
76 MeshSelection::clearEdgeSelection(triMesh);
77
78 // Iterate over all edges
79 for (e_it = triMesh->edges_begin(); e_it != e_end ; ++e_it) {
80 TriMesh::HalfedgeHandle he = triMesh->halfedge_handle( *e_it, 0 );
81 TriMesh::Point p1 = triMesh->point( triMesh->from_vertex_handle( he ) );
82 TriMesh::Point p2 = triMesh->point( triMesh->to_vertex_handle( he ) );
83
84 if ( _larger ) {
85 if ( (p1 - p2).norm() > _length)
86 triMesh->status(*e_it).set_selected(true);
87 } else {
88 if ( (p1 - p2).norm() < _length)
89 triMesh->status(*e_it).set_selected(true);
90 }
91 }
92
93 emit updatedObject(_objectId,UPDATE_SELECTION);
94 emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
95
96 return;
97 }
98
99 // get the target mesh
100 PolyMesh* polyMesh = 0;
101 PluginFunctions::getMesh(_objectId,polyMesh);
102
103 if ( polyMesh ) {
104 PolyMesh::EdgeIter e_it, e_end=polyMesh->edges_end();
105
106 // Clear current edge selection
107 MeshSelection::clearEdgeSelection(polyMesh);
108
109 // Iterate over all edges
110 for (e_it = polyMesh->edges_begin(); e_it != e_end ; ++e_it) {
111 PolyMesh::HalfedgeHandle he = polyMesh->halfedge_handle( *e_it, 0 );
112 PolyMesh::Point p1 = polyMesh->point( polyMesh->from_vertex_handle( he ) );
113 PolyMesh::Point p2 = polyMesh->point( polyMesh->to_vertex_handle( he ) );
114
115 if ( _larger ) {
116 if ( (p1 - p2).norm() > _length)
117 polyMesh->status(*e_it).set_selected(true);
118 } else {
119 if ( (p1 - p2).norm() < _length)
120 polyMesh->status(*e_it).set_selected(true);
121 }
122 }
123
124 emit updatedObject(_objectId,UPDATE_SELECTION);
125 emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
126
127 return;
128 }
129
130 emit log( LOGERR,tr("Unsupported Object Type for edge selection") );
131
132 }
133
134 //-----------------------------------------------------------------------------
135
136 void MeshRepairPlugin::removeSelectedEdges(int _objectId) {
137
138 // get the target mesh
139 TriMesh* triMesh = 0;
140
141 PluginFunctions::getMesh(_objectId, triMesh);
142
143 if (triMesh) {
144
145 TriMesh::EdgeIter e_it, e_end = triMesh->edges_end();
146
147 for (e_it = triMesh->edges_begin(); e_it != e_end; ++e_it) {
148
149 if (!triMesh->status(*e_it).deleted() && triMesh->status(*e_it).selected()) {
150
151 const TriMesh::VHandle v0 = triMesh->to_vertex_handle(triMesh->halfedge_handle(*e_it, 0));
152 const TriMesh::VHandle v1 = triMesh->to_vertex_handle(triMesh->halfedge_handle(*e_it, 1));
153
154 const bool boundary0 = triMesh->is_boundary(v0);
155 const bool boundary1 = triMesh->is_boundary(v1);
156
157 const bool feature0 = triMesh->status(v0).feature();
158 const bool feature1 = triMesh->status(v1).feature();
159 const bool featureE = triMesh->status(*e_it).feature();
160
161 // Collapsing v1 into vo:
162 // collapse is ok, if collapsed vertex is not a feature vertex or the target vertex is a feature
163 // and if we collapse along an feature edge or if the collapsed vertex is not a feature
164 if ((!boundary1 || boundary0) && (!feature1 || (feature0 && featureE)) && triMesh->is_collapse_ok(
165 triMesh->halfedge_handle(*e_it, 0)))
166 triMesh->collapse(triMesh->halfedge_handle(*e_it, 0));
167 else if ((!boundary0 || boundary1) && (!feature0 || (feature1 && featureE)) && triMesh->is_collapse_ok(
168 triMesh->halfedge_handle(*e_it, 1)))
169 triMesh->collapse(triMesh->halfedge_handle(*e_it, 1));
170 }
171 }
172
173 triMesh->garbage_collection();
174 triMesh->update_normals();
175
176 emit updatedObject(_objectId, UPDATE_ALL);
177 emit createBackup(_objectId, "Removed selected Edges", UPDATE_ALL);
178 emit scriptInfo("removeSelectedEdges(" + QString::number(_objectId) + ")");
179
180 return;
181 }
182
183 emit log(LOGERR, tr("Unsupported Object Type for edge removal"));
184
185 }
186
187
188
189 void MeshRepairPlugin::detectSkinnyTriangleByAngle(int _objectId, double _angle, bool _remove) {
190 // get the target mesh
191 TriMesh* triMesh = 0;
192
193 PluginFunctions::getMesh(_objectId, triMesh);
194
195 if (triMesh) {
196
197 // Clear current edge selection
198 MeshSelection::clearEdgeSelection(triMesh);
199
200 double maxAngle = cos(_angle * M_PI / 180.0);
201 double angle = 0.0;
202 TriMesh::EdgeIter e_it, e_end = triMesh->edges_end();
203
204 for (e_it = triMesh->edges_begin(); e_it != e_end; ++e_it) {
205
206 // Check prerequisites
207 if (!triMesh->status(*e_it).deleted() && !triMesh->status(*e_it).feature() && triMesh->is_flip_ok(*e_it)) {
208
209 // For both halfedges
210 for (unsigned int h = 0; h < 2; ++h) {
211 TriMesh::HalfedgeHandle hh = triMesh->halfedge_handle(*e_it, h);
212 const TriMesh::Point& a = triMesh->point(triMesh->from_vertex_handle(hh));
213 const TriMesh::Point& b = triMesh->point(triMesh->to_vertex_handle(hh));
214 hh = triMesh->next_halfedge_handle(hh);
215 const TriMesh::Point& c = triMesh->point(triMesh->to_vertex_handle(hh));
216
217 angle = ((a - c).normalize() | (b - c).normalize());
218
219 if (angle < maxAngle) {
220
221 // selcet it
222 triMesh->status(*e_it).set_selected(true);
223
224 // remove it if requested
225 if (_remove)
226 triMesh->flip(*e_it);
227 }
228 }
229 }
230 }
231
232 if (_remove) {
233 emit updatedObject(_objectId, UPDATE_ALL);
234 emit createBackup(_objectId, tr("Removed cap edges"), UPDATE_ALL);
235 } else {
236 emit updatedObject(_objectId, UPDATE_SELECTION);
237 emit createBackup(_objectId, tr("Selected cap edges"), UPDATE_ALL);
238 } emit
239 scriptInfo(
240 "detectSkinnyTriangleByAngle(" + QString::number(_objectId) + "," + QString::number(_angle) + ","
241 + _remove + ")");
242
243 return;
244 }
245
246 emit log(LOGERR, tr("Unsupported Object Type for Cap detection!"));
247 }
248
249 //-----------------------------------------------------------------------------
250
251
252 void MeshRepairPlugin::detectFoldover(int _objectId, float _angle) {
253
254 // get the target mesh
255 TriMeshObject* trimesh_o = 0;
256 PolyMeshObject* polymesh_o = 0;
257
258 PluginFunctions::getObject(_objectId, trimesh_o);
259 PluginFunctions::getObject(_objectId, polymesh_o);
260
261 unsigned int count = 0;
262
263 if (trimesh_o != 0) {
264
265 // get the target mesh
266 TriMesh* mesh = trimesh_o->mesh();
267
268 if (mesh) {
269
270 // Clear current edge selection
271 MeshSelection::clearEdgeSelection(mesh);
272
273 TriMesh::EdgeIter e_it, e_end(mesh->edges_end());
274 TriMesh::FaceHandle fh;
275 TriMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
276
277 for (e_it = mesh->edges_begin(); e_it != e_end; ++e_it) {
278 if (!mesh->is_boundary(*e_it)) {
279 a = (mesh->normal(mesh->face_handle(mesh->halfedge_handle(*e_it, 0))) | mesh->normal(
280 mesh->face_handle(mesh->halfedge_handle(*e_it, 1))));
281
282 if (a < cosa) {
283 mesh->status(mesh->edge_handle(mesh->halfedge_handle(*e_it, 0))). set_selected(true);
284 ++count;
285 }
286 }
287 }
288 }
289 } else if (polymesh_o != 0) {
290
291 // get the target mesh
292 PolyMesh* mesh = polymesh_o->mesh();
293
294 if (mesh) {
295
296 // Clear current edge selection
297 MeshSelection::clearEdgeSelection(mesh);
298
299 PolyMesh::EdgeIter e_it, e_end(mesh->edges_end());
300 PolyMesh::FaceHandle fh;
301 PolyMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
302
303 for (e_it = mesh->edges_begin(); e_it != e_end; ++e_it) {
304 if (!mesh->is_boundary(*e_it)) {
305 a = (mesh->normal(mesh->face_handle(mesh->halfedge_handle(*e_it, 0))) | mesh->normal(
306 mesh->face_handle(mesh->halfedge_handle(*e_it, 1))));
307
308 if (a < cosa) {
309 mesh->status(mesh->edge_handle(mesh->halfedge_handle(*e_it, 0))). set_selected(true);
310 ++count;
311 }
312 }
313 }
314 }
315 }
316
317 if (count > 0) {
318 emit updatedObject(_objectId, UPDATE_SELECTION);
319 emit createBackup(_objectId, "Select edges", UPDATE_SELECTION);
320 emit scriptInfo("detectFoldover(" + QString::number(_objectId) + ", " + QString::number(_angle) + ")");
321 }
322 emit log(
323 "Selected " + QString::number(count) + " fold-overs on object " + QString::number(_objectId)
324 + " with angle greater than " + QString::number(_angle) + ".");
325 }
326
327
328 //-----------------------------------------------------------------------------
LOGERR
Definition: LoggingInterface.hh:96
MeshRepairPlugin::detectSkinnyTriangleByAngle
void detectSkinnyTriangleByAngle(int _objectId, double _angle, bool _remove)
Detect/Remove edges where neighboring faces form angle > _angle degrees.
Definition: EdgeFunctions.cc:189
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
PolyMeshObject
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
OpenMesh::PolyMeshT::Point
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:296
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
UPDATE_SELECTION
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
MeshRepairPlugin::selectEdgesLongerThan
void selectEdgesLongerThan(int _objectId, double _length)
Selects all edges of an object which are larger than the given length.
Definition: EdgeFunctions.cc:56
OpenMesh::PolyMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:94
MeshObject::mesh
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT_impl.hh:350
MeshRepairPlugin::selectEdgesShorterThan
void selectEdgesShorterThan(int _objectId, double _length)
Selects all edges of an object which are shorter than the given length.
Definition: EdgeFunctions.cc:48
MeshRepairPlugin::selectionEdgeLength
void selectionEdgeLength(int _objectId, double _length, bool _larger)
select edges based on length
Definition: EdgeFunctions.cc:65
MeshRepairPlugin::removeSelectedEdges
void removeSelectedEdges(int _objectId)
Removes all selected edges.
Definition: EdgeFunctions.cc:136
MeshSelectionT.hh
Functions for selection on a mesh.
TriMeshObject
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
OpenMesh::PolyMeshT::update_normals
void update_normals()
Compute normals for all primitives.
Definition: PolyMeshT_impl.hh:317
OpenMesh::PolyMeshT::Scalar
Kernel::Scalar Scalar
Scalar type.
Definition: PolyMeshT.hh:110
PluginFunctions::getMesh
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
Definition: PluginFunctionsPolyMesh.cc:101
MeshRepairPlugin::detectFoldover
void detectFoldover(int _objectId, float _angle)
Detect folded-over configurations by the dihedral angle.
Definition: EdgeFunctions.cc:252