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 bool MeshObjectSelectionPlugin::selectEdge(int _objectId, int _idx, bool _fly_to_edge)
93 {
94  return selectElement(_objectId, OpenMesh::EdgeHandle(_idx), _fly_to_edge);
95 }
96 
97 //=========================================================
98 
99 void MeshObjectSelectionPlugin::unselectEdges( int objectId , IdList _edgeList ) {
100 
101  if(_edgeList.empty()) return;
102 
103  BaseObjectData* object;
104  if ( ! PluginFunctions::getObject(objectId,object) ) {
105  emit log(LOGERR,tr("unselectEdges : unable to get object") );
106  return;
107  }
108 
109  if ( object->dataType() == DATA_TRIANGLE_MESH )
110  MeshSelection::unselectEdges(PluginFunctions::triMesh(object), _edgeList);
111  else if ( object->dataType() == DATA_POLY_MESH )
112  MeshSelection::unselectEdges(PluginFunctions::polyMesh(object), _edgeList);
113  else {
114  emit log(LOGERR,tr("unselectEdges : Unsupported object Type") );
115  return;
116  }
117 
118  QString selection = "unselectVertices( ObjectId(" + QString::number(objectId) +") , [ " + QString::number(_edgeList[0]);
119 
120  for ( uint i = 1 ; i < _edgeList.size(); ++i) {
121  selection += " , " + QString::number(_edgeList[i]);
122  }
123 
124  selection += " ] )";
125 
126  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
127  emit scriptInfo( selection );
128 }
129 
130 //=========================================================
131 
133 
134  BaseObjectData* object;
135  if ( ! PluginFunctions::getObject(objectId,object) ) {
136  emit log(LOGERR,tr("selectAllVertices : unable to get object") );
137  return;
138  }
139 
140  if ( object->dataType() == DATA_TRIANGLE_MESH )
141  MeshSelection::selectAllEdges(PluginFunctions::triMesh(object));
142  else if ( object->dataType() == DATA_POLY_MESH )
143  MeshSelection::selectAllEdges(PluginFunctions::polyMesh(object));
144  else {
145  emit log(LOGERR,tr("selectAllEdges : Unsupported object Type") );
146  return;
147  }
148 
149  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
150  emit scriptInfo( "selectAllEdges( ObjectId(" + QString::number(objectId) + ") )" );
151 }
152 
153 //=========================================================
154 
156 
157  BaseObjectData* object;
158  if ( ! PluginFunctions::getObject(objectId,object) ) {
159  emit log(LOGERR,tr("clearEdgeSelection : unable to get object") );
160  return;
161  }
162 
163  if ( object->dataType() == DATA_TRIANGLE_MESH )
164  MeshSelection::clearEdgeSelection(PluginFunctions::triMesh(object));
165  else if ( object->dataType() == DATA_POLY_MESH )
166  MeshSelection::clearEdgeSelection(PluginFunctions::polyMesh(object));
167  else {
168  emit log(LOGERR,tr("clearEdgeSelection : Unsupported object Type") );
169  return;
170  }
171 
172  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
173  emit scriptInfo( "clearEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
174 }
175 
176 //=========================================================
177 
179 
180  BaseObjectData* object;
181  if ( ! PluginFunctions::getObject(objectId,object) ) {
182  emit log(LOGERR,tr("invertEdgeSelection : unable to get object") );
183  return;
184  }
185 
186  if ( object->dataType() == DATA_TRIANGLE_MESH )
187  MeshSelection::invertEdgeSelection(PluginFunctions::triMesh(object));
188  else if ( object->dataType() == DATA_POLY_MESH )
189  MeshSelection::invertEdgeSelection(PluginFunctions::polyMesh(object));
190  else {
191  emit log(LOGERR,tr("invertEdgeSelection : Unsupported object Type") );
192  return;
193  }
194 
195  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
196  emit scriptInfo( "invertEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
197 }
198 
199 //=========================================================
200 
202 
203  BaseObjectData* object;
204  if ( ! PluginFunctions::getObject(objectId,object) ) {
205  emit log(LOGERR,tr("selectBoundaryEdges : unable to get object") );
206  return;
207  }
208 
209  if ( object->dataType() == DATA_TRIANGLE_MESH )
210  MeshSelection::selectBoundaryEdges(PluginFunctions::triMesh(object));
211  else if ( object->dataType() == DATA_POLY_MESH )
212  MeshSelection::selectBoundaryEdges(PluginFunctions::polyMesh(object));
213  else {
214  emit log(LOGERR,tr("selectBoundaryEdges : Unsupported object Type") );
215  return;
216  }
217 
218  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
219  emit scriptInfo( "selectBoundaryEdges( ObjectId(" + QString::number(objectId) + ") )" );
220 }
221 
222 //=========================================================
223 
225 
226  BaseObjectData* object = 0;
227  if (!PluginFunctions::getObject(_objectId,object)) {
228  emit log(LOGERR,tr("deleteEdgeSelection: unable to get object"));
229  return;
230  }
231 
232  if (object->dataType() == DATA_TRIANGLE_MESH)
234  else if (object->dataType() == DATA_POLY_MESH)
236  else {
237  emit log(LOGERR,tr("deleteEdgeSelection: Unsupported object Type"));
238  return;
239  }
240 
241  emit updatedObject(object->id(), UPDATE_ALL);
242  emit scriptInfo("deleteEdgeSelection(ObjectId(" + QString::number(_objectId) + "))");
243 }
244 
245 //=========================================================
246 
248  return createMeshFromSelection(_objectId, edgeType_ );
249 }
250 
251 //=========================================================
252 
254 
255  BaseObjectData* object;
256  if ( ! PluginFunctions::getObject(objectId,object) ) {
257  emit log(LOGERR,tr("getEdgeSelection : unable to get object") );
258  return IdList(0);
259  }
260 
261  emit scriptInfo( "getEdgeSelection( ObjectId(" + QString::number(objectId) + ") )" );
262 
263  if ( object->dataType() == DATA_TRIANGLE_MESH )
264  return MeshSelection::getEdgeSelection(PluginFunctions::triMesh(object));
265  else if ( object->dataType() == DATA_POLY_MESH )
266  return MeshSelection::getEdgeSelection(PluginFunctions::polyMesh(object));
267  else {
268  emit log(LOGERR,tr("getEdgeSelection : Unsupported object Type") );
269  return IdList(0);
270  }
271 
272  return IdList(0);
273 
274 }
275 
276 //=========================================================
277 
279 
280  IdList vertex_pairs;
281 
282  BaseObjectData* object = 0;
283  if ( !PluginFunctions::getObject(_id,object) ) {
284  emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id));
285  return IdList(0);
286  }
287 
288  if(object->dataType() == DATA_TRIANGLE_MESH) {
289 
290  TriMeshObject* obj = 0;
291  if(!PluginFunctions::getObject(_id, obj)) {
292  emit log(LOGERR, "Could not get mesh object!");
293  return IdList(0);
294  }
295 
296  TriMesh* mesh = obj->mesh();
297 
298  for(IdList::const_iterator it = _edges.begin(); it != _edges.end(); ++it) {
299  vertex_pairs.push_back(mesh->from_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
300  vertex_pairs.push_back(mesh->to_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
301  }
302 
303  } else if(object->dataType() == DATA_POLY_MESH) {
304 
305  PolyMeshObject* obj = 0;
306  if(!PluginFunctions::getObject(_id, obj)) {
307  emit log(LOGERR, "Could not get mesh object!");
308  return IdList(0);
309  }
310 
311  PolyMesh* mesh = obj->mesh();
312 
313  for(IdList::const_iterator it = _edges.begin(); it != _edges.end(); ++it) {
314  vertex_pairs.push_back(mesh->from_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
315  vertex_pairs.push_back(mesh->to_vertex_handle(mesh->halfedge_handle(TriMesh::EdgeHandle(*it), 0)).idx());
316  }
317  }
318 
319  return vertex_pairs;
320 }
321 
322 //=========================================================
323 
325 
326  if(_vertices.size() % 2 != 0) {
327  emit log(LOGERR, "Number of vertices is not even!");
328  return IdList(0);
329  }
330 
331  IdList edges;
332 
333  BaseObjectData* object = 0;
334  if ( !PluginFunctions::getObject(_id,object) ) {
335  emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id));
336  return IdList(0);
337  }
338 
339  if(object->dataType() == DATA_TRIANGLE_MESH) {
340 
341  TriMeshObject* obj = 0;
342  if(!PluginFunctions::getObject(_id, obj)) {
343  emit log(LOGERR, "Could not get mesh object!");
344  return IdList(0);
345  }
346 
347  TriMesh* mesh = obj->mesh();
348 
349  for(IdList::const_iterator it = _vertices.begin(); it != _vertices.end(); it+=2) {
351  if(!vh.is_valid()) continue;
352  for(TriMesh::VertexOHalfedgeIter voh_it = mesh->voh_iter(vh);
353  voh_it.is_valid(); ++voh_it) {
354  if(mesh->to_vertex_handle(*voh_it).idx() == *(it+1)) {
355  edges.push_back(mesh->edge_handle(*voh_it).idx());
356  continue;
357  }
358  }
359  }
360 
361  } else if(object->dataType() == DATA_POLY_MESH) {
362 
363  PolyMeshObject* obj = 0;
364  if(!PluginFunctions::getObject(_id, obj)) {
365  emit log(LOGERR, "Could not get mesh object!");
366  return IdList(0);
367  }
368 
369  PolyMesh* mesh = obj->mesh();
370 
371  for(IdList::const_iterator it = _vertices.begin(); it != _vertices.end(); it+=2) {
373  if(!vh.is_valid()) continue;
374  for(PolyMesh::VertexOHalfedgeIter voh_it = mesh->voh_iter(vh);
375  voh_it.is_valid(); ++voh_it) {
376  if(mesh->to_vertex_handle(*voh_it).idx() == *(it+1)) {
377  edges.push_back(mesh->edge_handle(*voh_it).idx());
378  continue;
379  }
380  }
381  }
382  }
383 
384  return edges;
385 }
386 
387 //=========================================================
388 
389 void MeshObjectSelectionPlugin::colorizeEdgeSelection(int objectId, int r, int g, int b, int a ) {
390 
391  BaseObjectData* object;
392  if ( ! PluginFunctions::getObject(objectId,object) ) {
393  emit log(LOGERR,"colorizeEdgeSelection : unable to get object" );
394  return;
395  }
396 
397  if ( object->dataType() == DATA_TRIANGLE_MESH ) {
399  } else if ( object->dataType() == DATA_POLY_MESH ) {
401  } else {
402  emit log(LOGERR,"colorizeEdgeSelection : Unsupported object Type" );
403  return;
404  }
405 
406  emit scriptInfo( "colorizeEdgeSelection( ObjectId(" + QString::number(objectId) + "), "
407  + QString::number(r) + ", " + QString::number(g) + ", " + QString::number(b) + " )" );
408 
409  emit updatedObject(object->id(), UPDATE_COLOR);
410 }
411 
412 namespace {
413 
414 template<class MeshT>
415 inline bool edgeSelected(MeshT &mesh, typename MeshT::HalfedgeHandle he) {
416  return mesh.status(mesh.edge_handle(he)).selected();
417 }
418 template<class MeshT>
419 void traceEdgePath(MeshT &mesh, double threshold) {
420  typedef typename MeshT::HalfedgeIter HEIt;
421  typedef typename MeshT::VOHIter VOHIter;
422  typedef typename MeshT::HalfedgeHandle HEH;
423 
424  for (HEIt he_it = mesh.halfedges_begin(), he_end = mesh.halfedges_end();
425  he_it != he_end; ++he_it) {
426  if (edgeSelected(mesh, *he_it)) {
427 
428  HEH current_he = *he_it;
429 
430  for (bool tracing = true; tracing;) {
431  const typename MeshT::Normal cur_vec =
432  mesh.calc_edge_vector(current_he).normalized();
433  const HEH back_out_he = mesh.opposite_halfedge_handle(current_he);
434  HEH best_out_he;
435  double best_alignment = -std::numeric_limits<double>::infinity();
436  const typename MeshT::VertexHandle to_vtx =
437  mesh.to_vertex_handle(current_he);
438 
439  for (VOHIter voh_it = mesh.voh_begin(to_vtx),
440  voh_end = mesh.voh_end(to_vtx);
441  voh_it != voh_end; ++voh_it) {
442  if (*voh_it == back_out_he) continue;
443  if (edgeSelected(mesh, *voh_it)) {
444  tracing = false;
445  break;
446  }
447  const typename MeshT::Normal next_vec =
448  mesh.calc_edge_vector(*voh_it).normalized();
449  if (best_alignment < (cur_vec | next_vec)) {
450  best_alignment = (cur_vec | next_vec);
451  best_out_he = *voh_it;
452  }
453  }
454  if (tracing && best_alignment > threshold) {
455  current_he = best_out_he;
456  mesh.status(mesh.edge_handle(current_he)).set_selected(true);
457  } else {
458  tracing = false;
459  }
460  }
461  }
462  }
463 }
464 }
465 
466 void MeshObjectSelectionPlugin::traceEdgePath(int objectId, double threshold) {
467  BaseObjectData* object;
468  if ( ! PluginFunctions::getObject(objectId,object) ) {
469  emit log(LOGERR,"traceEdgePath: unable to get object" );
470  return;
471  }
472 
473  if ( object->dataType() == DATA_TRIANGLE_MESH ) {
474  ::traceEdgePath(*PluginFunctions::triMesh(object), threshold);
475  } else if ( object->dataType() == DATA_POLY_MESH ) {
476  ::traceEdgePath(*PluginFunctions::polyMesh(object), threshold);
477  } else {
478  emit log(LOGERR,"traceEdgePath: Unsupported object Type" );
479  return;
480  }
481 
482  emit scriptInfo(QString::fromUtf8("traceEdgePath(ObjectId(%1), %2)")
483  .arg(objectId).arg(threshold));
484 
485  emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
486 }
void selectEdges(int objectId, IdList _edgeList, const double _dihedral_angle_threshold=0.0)
Select given Edges.
Handle for a edge entity.
Definition: Handles.hh:134
void deleteEdgeSelection(int _objectId)
Delete edges that are currently selected.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
void selectBoundaryEdges(int objectId)
select boundary edges
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
int createMeshFromEdgeSelection(int _objectId)
Create a mesh containing the face selection of the given mesh.
void selectAllEdges(int objectId)
Select all Edges.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
IdList convertVertexPairsToEdges(int _id, const IdList &_vertices)
Inverse of function above.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
bool deleteSelection(MeshT *_mesh, PrimitiveType _primitiveType)
Delete all selected elements of a mesh.
int id() const
Definition: BaseObject.cc:190
MeshT * mesh()
return a pointer to the mesh
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
Kernel::VertexOHalfedgeIter VertexOHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:163
void update_dihedral_angle_threshold_from_ui()
set dihedral angle threshold for edge selection
void traceEdgePath(int objectId, double threshold)
Trace Edge Path.
void colorizeEdgeSelection(int objectId, int r, int g, int b, int a)
Colorize the edge selection.
Functions for selection on a mesh.
void unselectEdges(int objectId, IdList _edgeList)
Unselect given Edges.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
const UpdateType UPDATE_SELECTION_EDGES(UpdateTypeSet(1)<< 6)
Edge selection has changed.
SelectionInterface::PrimitiveType edgeType_
Handle to selection environment.
void createMeshFromSelection(MeshT &_mesh, MeshT &_newMesh, PrimitiveType _primitiveType)
Create a new mesh from the selection.
void colorizeSelection(MeshT *_mesh, PrimitiveType _primitiveTypes, int _red, int _green, int _blue, int _alpha)
Colorize the selection.
bool selectEdge(int _objectId, int _idx, bool _fly_to_edge)
Select edge with id _idx and maybe fly to it.
bool selectElement(int _objectId, HandleT _handle, bool _fly_to_element)
set dihedral angle threshold for edge selection
IdList convertEdgesToVertexPairs(int _id, const IdList &_edges)
Convert edge ids to vertex pairs.
IdList getEdgeSelection(int objectId)
Return a list of all selected edges.
void invertEdgeSelection(int objectId)
Unselect all Edges.
void clearEdgeSelection(int objectId)
Invert the current edge selection.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
const UpdateType UPDATE_COLOR(UpdateTypeSet(1)<< 10)
Colors have changed.