Developer Documentation
EdgeSelection.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 #include "MeshObjectSelectionPlugin.hh"
51 
53 
54 //=========================================================
55 //==== Edge selections
56 //=========================================================
57 
58 void MeshObjectSelectionPlugin::selectEdges( int objectId , IdList _edgeList, const double _dihedral_angle_threshold ) {
60 
61  if(_edgeList.empty() ) return;
62 
63  BaseObjectData* object = 0;
64  if ( ! PluginFunctions::getObject(objectId,object) ) {
65  emit log(LOGERR,tr("selectEdges : unable to get object") );
66  return;
67  }
68 
69  if ( object->dataType() == DATA_TRIANGLE_MESH )
70  MeshSelection::selectEdges(PluginFunctions::triMesh(object), _edgeList, _dihedral_angle_threshold);
71  else if ( object->dataType() == DATA_POLY_MESH )
72  MeshSelection::selectEdges(PluginFunctions::polyMesh(object), _edgeList, _dihedral_angle_threshold);
73  else {
74  emit log(LOGERR,tr("selectEdges : Unsupported object Type") );
75  return;
76  }
77 
78  QString selection = "selectEdges( ObjectId(" + QString::number(objectId) + ") , [ " + QString::number(_edgeList[0]);
79 
80  for ( uint i = 1 ; i < _edgeList.size(); ++i) {
81  selection += " , " + QString::number(_edgeList[i]);
82  }
83 
84  selection += " ] )";
85 
86  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES );
87  emit scriptInfo( selection );
88 }
89 
90 //=========================================================
91 
92 void MeshObjectSelectionPlugin::unselectEdges( int objectId , IdList _edgeList ) {
93 
94  if(_edgeList.empty()) return;
95 
96  BaseObjectData* object;
97  if ( ! PluginFunctions::getObject(objectId,object) ) {
98  emit log(LOGERR,tr("unselectEdges : unable to get object") );
99  return;
100  }
101 
102  if ( object->dataType() == DATA_TRIANGLE_MESH )
103  MeshSelection::unselectEdges(PluginFunctions::triMesh(object), _edgeList);
104  else if ( object->dataType() == DATA_POLY_MESH )
105  MeshSelection::unselectEdges(PluginFunctions::polyMesh(object), _edgeList);
106  else {
107  emit log(LOGERR,tr("unselectEdges : Unsupported object Type") );
108  return;
109  }
110 
111  QString selection = "unselectVertices( ObjectId(" + QString::number(objectId) +") , [ " + QString::number(_edgeList[0]);
112 
113  for ( uint i = 1 ; i < _edgeList.size(); ++i) {
114  selection += " , " + QString::number(_edgeList[i]);
115  }
116 
117  selection += " ] )";
118 
119  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
120  emit scriptInfo( selection );
121 }
122 
123 //=========================================================
124 
126 
127  BaseObjectData* object;
128  if ( ! PluginFunctions::getObject(objectId,object) ) {
129  emit log(LOGERR,tr("selectAllVertices : unable to get object") );
130  return;
131  }
132 
133  if ( object->dataType() == DATA_TRIANGLE_MESH )
134  MeshSelection::selectAllEdges(PluginFunctions::triMesh(object));
135  else if ( object->dataType() == DATA_POLY_MESH )
136  MeshSelection::selectAllEdges(PluginFunctions::polyMesh(object));
137  else {
138  emit log(LOGERR,tr("selectAllEdges : Unsupported object Type") );
139  return;
140  }
141 
142  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
143  emit scriptInfo( "selectAllEdges( ObjectId(" + QString::number(objectId) + ") )" );
144 }
145 
146 //=========================================================
147 
149 
150  BaseObjectData* object;
151  if ( ! PluginFunctions::getObject(objectId,object) ) {
152  emit log(LOGERR,tr("clearEdgeSelection : unable to get object") );
153  return;
154  }
155 
156  if ( object->dataType() == DATA_TRIANGLE_MESH )
157  MeshSelection::clearEdgeSelection(PluginFunctions::triMesh(object));
158  else if ( object->dataType() == DATA_POLY_MESH )
159  MeshSelection::clearEdgeSelection(PluginFunctions::polyMesh(object));
160  else {
161  emit log(LOGERR,tr("clearEdgeSelection : Unsupported object Type") );
162  return;
163  }
164 
165  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
166  emit scriptInfo( "clearEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
167 }
168 
169 //=========================================================
170 
172 
173  BaseObjectData* object;
174  if ( ! PluginFunctions::getObject(objectId,object) ) {
175  emit log(LOGERR,tr("invertEdgeSelection : unable to get object") );
176  return;
177  }
178 
179  if ( object->dataType() == DATA_TRIANGLE_MESH )
180  MeshSelection::invertEdgeSelection(PluginFunctions::triMesh(object));
181  else if ( object->dataType() == DATA_POLY_MESH )
182  MeshSelection::invertEdgeSelection(PluginFunctions::polyMesh(object));
183  else {
184  emit log(LOGERR,tr("invertEdgeSelection : Unsupported object Type") );
185  return;
186  }
187 
188  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
189  emit scriptInfo( "invertEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
190 }
191 
192 //=========================================================
193 
195 
196  BaseObjectData* object;
197  if ( ! PluginFunctions::getObject(objectId,object) ) {
198  emit log(LOGERR,tr("selectBoundaryEdges : unable to get object") );
199  return;
200  }
201 
202  if ( object->dataType() == DATA_TRIANGLE_MESH )
203  MeshSelection::selectBoundaryEdges(PluginFunctions::triMesh(object));
204  else if ( object->dataType() == DATA_POLY_MESH )
205  MeshSelection::selectBoundaryEdges(PluginFunctions::polyMesh(object));
206  else {
207  emit log(LOGERR,tr("selectBoundaryEdges : Unsupported object Type") );
208  return;
209  }
210 
211  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
212  emit scriptInfo( "selectBoundaryEdges( ObjectId(" + QString::number(objectId) + ") )" );
213 }
214 
215 //=========================================================
216 
218 
219  BaseObjectData* object = 0;
220  if (!PluginFunctions::getObject(_objectId,object)) {
221  emit log(LOGERR,tr("deleteEdgeSelection: unable to get object"));
222  return;
223  }
224 
225  if (object->dataType() == DATA_TRIANGLE_MESH)
227  else if (object->dataType() == DATA_POLY_MESH)
229  else {
230  emit log(LOGERR,tr("deleteEdgeSelection: Unsupported object Type"));
231  return;
232  }
233 
234  emit updatedObject(object->id(), UPDATE_ALL);
235  emit scriptInfo("deleteEdgeSelection(ObjectId(" + QString::number(_objectId) + "))");
236 }
237 
238 //=========================================================
239 
241  return createMeshFromSelection(_objectId, edgeType_ );
242 }
243 
244 //=========================================================
245 
247 
248  BaseObjectData* object;
249  if ( ! PluginFunctions::getObject(objectId,object) ) {
250  emit log(LOGERR,tr("getEdgeSelection : unable to get object") );
251  return IdList(0);
252  }
253 
254  emit scriptInfo( "getEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
255 
256  if ( object->dataType() == DATA_TRIANGLE_MESH )
257  return MeshSelection::getEdgeSelection(PluginFunctions::triMesh(object));
258  else if ( object->dataType() == DATA_POLY_MESH )
259  return MeshSelection::getEdgeSelection(PluginFunctions::polyMesh(object));
260  else {
261  emit log(LOGERR,tr("getEdgeSelection : Unsupported object Type") );
262  return IdList(0);
263  }
264 
265  return IdList(0);
266 
267 }
268 
269 //=========================================================
270 
272 
273  IdList vertex_pairs;
274 
275  BaseObjectData* object = 0;
276  if ( !PluginFunctions::getObject(_id,object) ) {
277  emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id));
278  return IdList(0);
279  }
280 
281  if(object->dataType() == DATA_TRIANGLE_MESH) {
282 
283  TriMeshObject* obj = 0;
284  if(!PluginFunctions::getObject(_id, obj)) {
285  emit log(LOGERR, "Could not get mesh object!");
286  return IdList(0);
287  }
288 
289  TriMesh* mesh = obj->mesh();
290 
291  for(IdList::const_iterator it = _edges.begin(); it != _edges.end(); ++it) {
292  vertex_pairs.push_back(mesh->from_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
293  vertex_pairs.push_back(mesh->to_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
294  }
295 
296  } else if(object->dataType() == DATA_POLY_MESH) {
297 
298  PolyMeshObject* obj = 0;
299  if(!PluginFunctions::getObject(_id, obj)) {
300  emit log(LOGERR, "Could not get mesh object!");
301  return IdList(0);
302  }
303 
304  PolyMesh* mesh = obj->mesh();
305 
306  for(IdList::const_iterator it = _edges.begin(); it != _edges.end(); ++it) {
307  vertex_pairs.push_back(mesh->from_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
308  vertex_pairs.push_back(mesh->to_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
309  }
310  }
311 
312  return vertex_pairs;
313 }
314 
315 //=========================================================
316 
318 
319  if(_vertices.size() % 2 != 0) {
320  emit log(LOGERR, "Number of vertices is not even!");
321  return IdList(0);
322  }
323 
324  IdList edges;
325 
326  BaseObjectData* object = 0;
327  if ( !PluginFunctions::getObject(_id,object) ) {
328  emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id));
329  return IdList(0);
330  }
331 
332  if(object->dataType() == DATA_TRIANGLE_MESH) {
333 
334  TriMeshObject* obj = 0;
335  if(!PluginFunctions::getObject(_id, obj)) {
336  emit log(LOGERR, "Could not get mesh object!");
337  return IdList(0);
338  }
339 
340  TriMesh* mesh = obj->mesh();
341 
342  for(IdList::const_iterator it = _vertices.begin(); it != _vertices.end(); it+=2) {
344  if(!vh.is_valid()) continue;
345  for(TriMesh::VertexOHalfedgeIter voh_it = mesh->voh_iter(vh);
346  voh_it.is_valid(); ++voh_it) {
347  if(mesh->to_vertex_handle(*voh_it).idx() == *(it+1)) {
348  edges.push_back(mesh->edge_handle(*voh_it).idx());
349  continue;
350  }
351  }
352  }
353 
354  } else if(object->dataType() == DATA_POLY_MESH) {
355 
356  PolyMeshObject* obj = 0;
357  if(!PluginFunctions::getObject(_id, obj)) {
358  emit log(LOGERR, "Could not get mesh object!");
359  return IdList(0);
360  }
361 
362  PolyMesh* mesh = obj->mesh();
363 
364  for(IdList::const_iterator it = _vertices.begin(); it != _vertices.end(); it+=2) {
366  if(!vh.is_valid()) continue;
367  for(PolyMesh::VertexOHalfedgeIter voh_it = mesh->voh_iter(vh);
368  voh_it.is_valid(); ++voh_it) {
369  if(mesh->to_vertex_handle(*voh_it).idx() == *(it+1)) {
370  edges.push_back(mesh->edge_handle(*voh_it).idx());
371  continue;
372  }
373  }
374  }
375  }
376 
377  return edges;
378 }
379 
380 //=========================================================
381 
382 void MeshObjectSelectionPlugin::colorizeEdgeSelection(int objectId, int r, int g, int b, int a ) {
383 
384  BaseObjectData* object;
385  if ( ! PluginFunctions::getObject(objectId,object) ) {
386  emit log(LOGERR,"colorizeEdgeSelection : unable to get object" );
387  return;
388  }
389 
390  if ( object->dataType() == DATA_TRIANGLE_MESH ) {
392  } else if ( object->dataType() == DATA_POLY_MESH ) {
394  } else {
395  emit log(LOGERR,"colorizeEdgeSelection : Unsupported object Type" );
396  return;
397  }
398 
399  emit scriptInfo( "colorizeEdgeSelection( ObjectId(" + QString::number(objectId) + "), "
400  + QString::number(r) + ", " + QString::number(g) + ", " + QString::number(b) + " )" );
401 
402  emit updatedObject(object->id(), UPDATE_COLOR);
403 }
404 
405 namespace {
406 
407 template<class MeshT>
408 inline bool edgeSelected(MeshT &mesh, typename MeshT::HalfedgeHandle he) {
409  return mesh.status(mesh.edge_handle(he)).selected();
410 }
411 template<class MeshT>
412 void traceEdgePath(MeshT &mesh, double threshold) {
413  typedef typename MeshT::HalfedgeIter HEIt;
414  typedef typename MeshT::VOHIter VOHIter;
415  typedef typename MeshT::HalfedgeHandle HEH;
416 
417  for (HEIt he_it = mesh.halfedges_begin(), he_end = mesh.halfedges_end();
418  he_it != he_end; ++he_it) {
419  if (edgeSelected(mesh, *he_it)) {
420 
421  HEH current_he = *he_it;
422 
423  for (bool tracing = true; tracing;) {
424  const typename MeshT::Normal cur_vec =
425  mesh.calc_edge_vector(current_he).normalized();
426  const HEH back_out_he = mesh.opposite_halfedge_handle(current_he);
427  HEH best_out_he;
428  double best_alignment = -std::numeric_limits<double>::infinity();
429  const typename MeshT::VertexHandle to_vtx =
430  mesh.to_vertex_handle(current_he);
431 
432  for (VOHIter voh_it = mesh.voh_begin(to_vtx),
433  voh_end = mesh.voh_end(to_vtx);
434  voh_it != voh_end; ++voh_it) {
435  if (*voh_it == back_out_he) continue;
436  if (edgeSelected(mesh, *voh_it)) {
437  tracing = false;
438  break;
439  }
440  const typename MeshT::Normal next_vec =
441  mesh.calc_edge_vector(*voh_it).normalized();
442  if (best_alignment < (cur_vec | next_vec)) {
443  best_alignment = (cur_vec | next_vec);
444  best_out_he = *voh_it;
445  }
446  }
447  if (tracing && best_alignment > threshold) {
448  current_he = best_out_he;
449  mesh.status(mesh.edge_handle(current_he)).set_selected(true);
450  } else {
451  tracing = false;
452  }
453  }
454  }
455  }
456 }
457 }
458 
459 void MeshObjectSelectionPlugin::traceEdgePath(int objectId, double threshold) {
460  BaseObjectData* object;
461  if ( ! PluginFunctions::getObject(objectId,object) ) {
462  emit log(LOGERR,"traceEdgePath: unable to get object" );
463  return;
464  }
465 
466  if ( object->dataType() == DATA_TRIANGLE_MESH ) {
467  ::traceEdgePath(*PluginFunctions::triMesh(object), threshold);
468  } else if ( object->dataType() == DATA_POLY_MESH ) {
469  ::traceEdgePath(*PluginFunctions::polyMesh(object), threshold);
470  } else {
471  emit log(LOGERR,"traceEdgePath: Unsupported object Type" );
472  return;
473  }
474 
475  emit scriptInfo(QString::fromUtf8("traceEdgePath(ObjectId(%1), %2)")
476  .arg(objectId).arg(threshold));
477 
478  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
479 }
void invertEdgeSelection(int objectId)
Unselect all Edges.
int createMeshFromEdgeSelection(int _objectId)
Create a mesh containing the face selection of the given mesh.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
Kernel::VertexOHalfedgeIter VertexOHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:163
int id() const
Definition: BaseObject.cc:190
void colorizeEdgeSelection(int objectId, int r, int g, int b, int a)
Colorize the edge selection.
void createMeshFromSelection(MeshT &_mesh, MeshT &_newMesh, PrimitiveType _primitiveType)
Create a new mesh from the selection.
IdList convertEdgesToVertexPairs(int _id, const IdList &_edges)
Convert edge ids to vertex pairs.
void clearEdgeSelection(int objectId)
Invert the current edge selection.
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
MeshT * mesh()
return a pointer to the mesh
bool deleteSelection(MeshT *_mesh, PrimitiveType _primitiveType)
Delete all selected elements of a mesh.
void colorizeSelection(MeshT *_mesh, PrimitiveType _primitiveTypes, int _red, int _green, int _blue, int _alpha)
Colorize the selection.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void selectAllEdges(int objectId)
Select all Edges.
void unselectEdges(int objectId, IdList _edgeList)
Unselect given Edges.
SelectionInterface::PrimitiveType edgeType_
Handle to selection environment.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
void update_dihedral_angle_threshold_from_ui()
set dihedral angle threshold for edge selection
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
Functions for selection on a mesh.
void selectBoundaryEdges(int objectId)
select boundary edges
void deleteEdgeSelection(int _objectId)
Delete edges that are currently selected.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
void selectEdges(int objectId, IdList _edgeList, const double _dihedral_angle_threshold=0.0)
Select given Edges.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
const UpdateType UPDATE_SELECTION_EDGES(UpdateTypeSet(1)<< 6)
Edge selection has changed.
const UpdateType UPDATE_COLOR(UpdateTypeSet(1)<< 10)
Colors have changed.
IdList getEdgeSelection(int objectId)
Return a list of all selected edges.
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
void traceEdgePath(int objectId, double threshold)
Trace Edge Path.
IdList convertVertexPairsToEdges(int _id, const IdList &_vertices)
Inverse of function above.