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 /*===========================================================================*\
44  * *
45  * $Revision$ *
46  * $LastChangedBy$ *
47  * $Date$ *
48  * *
49 \*===========================================================================*/
50 
51 
52 
53 
54 #include "MeshRepairPlugin.hh"
56 
57 //-----------------------------------------------------------------------------
58 
59 void MeshRepairPlugin::selectEdgesShorterThan(int _objectId,double _length) {
60  selectionEdgeLength(_objectId,_length,false);
61 
62  emit scriptInfo( "selectEdgesShorterThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
63 }
64 
65 //-----------------------------------------------------------------------------
66 
67 void MeshRepairPlugin::selectEdgesLongerThan(int _objectId,double _length) {
68  selectionEdgeLength(_objectId,_length,true);
69 
70  emit scriptInfo( "selectEdgesLongerThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
71 }
72 
73 //-----------------------------------------------------------------------------
74 
75 
76 void MeshRepairPlugin::selectionEdgeLength(int _objectId, double _length, bool _larger) {
77 
78  // get the target mesh
79  TriMesh* triMesh = 0;
80 
81  PluginFunctions::getMesh(_objectId,triMesh);
82 
83  if ( triMesh ) {
84  TriMesh::EdgeIter e_it, e_end=triMesh->edges_end();
85 
86  // Clear current edge selection
87  MeshSelection::clearEdgeSelection(triMesh);
88 
89  // Iterate over all edges
90  for (e_it = triMesh->edges_begin(); e_it != e_end ; ++e_it) {
91  TriMesh::HalfedgeHandle he = triMesh->halfedge_handle( *e_it, 0 );
92  TriMesh::Point p1 = triMesh->point( triMesh->from_vertex_handle( he ) );
93  TriMesh::Point p2 = triMesh->point( triMesh->to_vertex_handle( he ) );
94 
95  if ( _larger ) {
96  if ( (p1 - p2).norm() > _length)
97  triMesh->status(*e_it).set_selected(true);
98  } else {
99  if ( (p1 - p2).norm() < _length)
100  triMesh->status(*e_it).set_selected(true);
101  }
102  }
103 
104  emit updatedObject(_objectId,UPDATE_SELECTION);
105  emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
106 
107  return;
108  }
109 
110  // get the target mesh
111  PolyMesh* polyMesh = 0;
112  PluginFunctions::getMesh(_objectId,polyMesh);
113 
114  if ( polyMesh ) {
115  PolyMesh::EdgeIter e_it, e_end=polyMesh->edges_end();
116 
117  // Clear current edge selection
118  MeshSelection::clearEdgeSelection(polyMesh);
119 
120  // Iterate over all edges
121  for (e_it = polyMesh->edges_begin(); e_it != e_end ; ++e_it) {
122  PolyMesh::HalfedgeHandle he = polyMesh->halfedge_handle( *e_it, 0 );
123  PolyMesh::Point p1 = polyMesh->point( polyMesh->from_vertex_handle( he ) );
124  PolyMesh::Point p2 = polyMesh->point( polyMesh->to_vertex_handle( he ) );
125 
126  if ( _larger ) {
127  if ( (p1 - p2).norm() > _length)
128  polyMesh->status(*e_it).set_selected(true);
129  } else {
130  if ( (p1 - p2).norm() < _length)
131  polyMesh->status(*e_it).set_selected(true);
132  }
133  }
134 
135  emit updatedObject(_objectId,UPDATE_SELECTION);
136  emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
137 
138  return;
139  }
140 
141  emit log( LOGERR,tr("Unsupported Object Type for edge selection") );
142 
143 }
144 
145 //-----------------------------------------------------------------------------
146 
148 
149  // get the target mesh
150  TriMesh* triMesh = 0;
151 
152  PluginFunctions::getMesh(_objectId, triMesh);
153 
154  if (triMesh) {
155 
156  TriMesh::EdgeIter e_it, e_end = triMesh->edges_end();
157 
158  for (e_it = triMesh->edges_begin(); e_it != e_end; ++e_it) {
159 
160  if (!triMesh->status(*e_it).deleted() && triMesh->status(*e_it).selected()) {
161 
162  const TriMesh::VHandle v0 = triMesh->to_vertex_handle(triMesh->halfedge_handle(*e_it, 0));
163  const TriMesh::VHandle v1 = triMesh->to_vertex_handle(triMesh->halfedge_handle(*e_it, 1));
164 
165  const bool boundary0 = triMesh->is_boundary(v0);
166  const bool boundary1 = triMesh->is_boundary(v1);
167 
168  const bool feature0 = triMesh->status(v0).feature();
169  const bool feature1 = triMesh->status(v1).feature();
170  const bool featureE = triMesh->status(*e_it).feature();
171 
172  // Collapsing v1 into vo:
173  // collapse is ok, if collapsed vertex is not a feature vertex or the target vertex is a feature
174  // and if we collapse along an feature edge or if the collapsed vertex is not a feature
175  if ((!boundary1 || boundary0) && (!feature1 || (feature0 && featureE)) && triMesh->is_collapse_ok(
176  triMesh->halfedge_handle(*e_it, 0)))
177  triMesh->collapse(triMesh->halfedge_handle(*e_it, 0));
178  else if ((!boundary0 || boundary1) && (!feature0 || (feature1 && featureE)) && triMesh->is_collapse_ok(
179  triMesh->halfedge_handle(*e_it, 1)))
180  triMesh->collapse(triMesh->halfedge_handle(*e_it, 1));
181  }
182  }
183 
184  triMesh->garbage_collection();
185  triMesh->update_normals();
186 
187  emit updatedObject(_objectId, UPDATE_ALL);
188  emit createBackup(_objectId, "Removed selected Edges", UPDATE_ALL);
189  emit scriptInfo("removeSelectedEdges(" + QString::number(_objectId) + ")");
190 
191  return;
192  }
193 
194  emit log(LOGERR, tr("Unsupported Object Type for edge removal"));
195 
196 }
197 
198 
199 
200 void MeshRepairPlugin::detectSkinnyTriangleByAngle(int _objectId, double _angle, bool _remove) {
201  // get the target mesh
202  TriMesh* triMesh = 0;
203 
204  PluginFunctions::getMesh(_objectId, triMesh);
205 
206  if (triMesh) {
207 
208  // Clear current edge selection
209  MeshSelection::clearEdgeSelection(triMesh);
210 
211  double maxAngle = cos(_angle * M_PI / 180.0);
212  double angle = 0.0;
213  TriMesh::EdgeIter e_it, e_end = triMesh->edges_end();
214 
215  for (e_it = triMesh->edges_begin(); e_it != e_end; ++e_it) {
216 
217  // Check prerequisites
218  if (!triMesh->status(*e_it).deleted() && !triMesh->status(*e_it).feature() && triMesh->is_flip_ok(*e_it)) {
219 
220  // For both halfedges
221  for (unsigned int h = 0; h < 2; ++h) {
222  TriMesh::HalfedgeHandle hh = triMesh->halfedge_handle(*e_it, h);
223  const TriMesh::Point& a = triMesh->point(triMesh->from_vertex_handle(hh));
224  const TriMesh::Point& b = triMesh->point(triMesh->to_vertex_handle(hh));
225  hh = triMesh->next_halfedge_handle(hh);
226  const TriMesh::Point& c = triMesh->point(triMesh->to_vertex_handle(hh));
227 
228  angle = ((a - c).normalize() | (b - c).normalize());
229 
230  if (angle < maxAngle) {
231 
232  // selcet it
233  triMesh->status(*e_it).set_selected(true);
234 
235  // remove it if requested
236  if (_remove)
237  triMesh->flip(*e_it);
238  }
239  }
240  }
241  }
242 
243  if (_remove) {
244  emit updatedObject(_objectId, UPDATE_ALL);
245  emit createBackup(_objectId, tr("Removed cap edges"), UPDATE_ALL);
246  } else {
247  emit updatedObject(_objectId, UPDATE_SELECTION);
248  emit createBackup(_objectId, tr("Selected cap edges"), UPDATE_ALL);
249  } emit
250  scriptInfo(
251  "detectSkinnyTriangleByAngle(" + QString::number(_objectId) + "," + QString::number(_angle) + ","
252  + _remove + ")");
253 
254  return;
255  }
256 
257  emit log(LOGERR, tr("Unsupported Object Type for Cap detection!"));
258 }
259 
260 //-----------------------------------------------------------------------------
261 
262 
263 void MeshRepairPlugin::detectFoldover(int _objectId, float _angle) {
264 
265  // get the target mesh
266  TriMeshObject* trimesh_o = 0;
267  PolyMeshObject* polymesh_o = 0;
268 
269  PluginFunctions::getObject(_objectId, trimesh_o);
270  PluginFunctions::getObject(_objectId, polymesh_o);
271 
272  unsigned int count = 0;
273 
274  if (trimesh_o != 0) {
275 
276  // get the target mesh
277  TriMesh* mesh = trimesh_o->mesh();
278 
279  if (mesh) {
280 
281  // Clear current edge selection
282  MeshSelection::clearEdgeSelection(mesh);
283 
284  TriMesh::EdgeIter e_it, e_end(mesh->edges_end());
285  TriMesh::FaceHandle fh;
286  TriMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
287 
288  for (e_it = mesh->edges_begin(); e_it != e_end; ++e_it) {
289  if (!mesh->is_boundary(*e_it)) {
290  a = (mesh->normal(mesh->face_handle(mesh->halfedge_handle(*e_it, 0))) | mesh->normal(
291  mesh->face_handle(mesh->halfedge_handle(*e_it, 1))));
292 
293  if (a < cosa) {
294  mesh->status(mesh->edge_handle(mesh->halfedge_handle(*e_it, 0))). set_selected(true);
295  ++count;
296  }
297  }
298  }
299  }
300  } else if (polymesh_o != 0) {
301 
302  // get the target mesh
303  PolyMesh* mesh = polymesh_o->mesh();
304 
305  if (mesh) {
306 
307  // Clear current edge selection
308  MeshSelection::clearEdgeSelection(mesh);
309 
310  PolyMesh::EdgeIter e_it, e_end(mesh->edges_end());
311  PolyMesh::FaceHandle fh;
312  PolyMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
313 
314  for (e_it = mesh->edges_begin(); e_it != e_end; ++e_it) {
315  if (!mesh->is_boundary(*e_it)) {
316  a = (mesh->normal(mesh->face_handle(mesh->halfedge_handle(*e_it, 0))) | mesh->normal(
317  mesh->face_handle(mesh->halfedge_handle(*e_it, 1))));
318 
319  if (a < cosa) {
320  mesh->status(mesh->edge_handle(mesh->halfedge_handle(*e_it, 0))). set_selected(true);
321  ++count;
322  }
323  }
324  }
325  }
326  }
327 
328  if (count > 0) {
329  emit updatedObject(_objectId, UPDATE_SELECTION);
330  emit createBackup(_objectId, "Select edges", UPDATE_SELECTION);
331  emit scriptInfo("detectFoldover(" + QString::number(_objectId) + ", " + QString::number(_angle) + ")");
332  }
333  emit log(
334  "Selected " + QString::number(count) + " fold-overs on object " + QString::number(_objectId)
335  + " with angle greater than " + QString::number(_angle) + ".");
336 }
337 
338 
339 //-----------------------------------------------------------------------------
void detectFoldover(int _objectId, float _angle)
Detect folded-over configurations by the dihedral angle.
void detectSkinnyTriangleByAngle(int _objectId, double _angle, bool _remove)
Detect/Remove edges where neighboring faces form angle > _angle degrees.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
void update_normals()
Compute normals for all primitives.
Definition: PolyMeshT.cc:241
void selectEdgesLongerThan(int _objectId, double _length)
Selects all edges of an object which are larger than the given length.
bool getObject(int _identifier, BSplineCurveObject *&_object)
void selectEdgesShorterThan(int _objectId, double _length)
Selects all edges of an object which are shorter than the given length.
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT.cc:351
void selectionEdgeLength(int _objectId, double _length, bool _larger)
select edges based on length
Functions for selection on a mesh.
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
void removeSelectedEdges(int _objectId)
Removes all selected edges.
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:70
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:115
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
Kernel::Scalar Scalar
Scalar type.
Definition: PolyMeshT.hh:113