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
58void 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
92bool 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
99void 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(auto it : _edges) {
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(auto it : _edges) {
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) {
350 OpenMesh::SmartVertexHandle vh = make_smart(TriMesh::VertexHandle(*it), mesh);
351 if(!vh.is_valid()) continue;
352 for(auto voh_it : vh.outgoing_halfedges()) {
353 if(voh_it.to().idx() == *(it+1)) {
354 edges.push_back(voh_it.edge().idx());
355 continue;
356 }
357 }
358 }
359
360 } else if(object->dataType() == DATA_POLY_MESH) {
361
362 PolyMeshObject* obj = 0;
363 if(!PluginFunctions::getObject(_id, obj)) {
364 emit log(LOGERR, "Could not get mesh object!");
365 return IdList(0);
366 }
367
368 PolyMesh* mesh = obj->mesh();
369
370 for(IdList::const_iterator it = _vertices.begin(); it != _vertices.end(); it+=2) {
372 if(!vh.is_valid()) continue;
373 for(auto voh_it : vh.outgoing_halfedges()) {
374 if(voh_it.to().idx() == *(it+1)) {
375 edges.push_back(voh_it.edge().idx());
376 continue;
377 }
378 }
379 }
380 }
381
382 return edges;
383}
384
385//=========================================================
386
387void MeshObjectSelectionPlugin::colorizeEdgeSelection(int objectId, int r, int g, int b, int a ) {
388
389 BaseObjectData* object;
390 if ( ! PluginFunctions::getObject(objectId,object) ) {
391 emit log(LOGERR,"colorizeEdgeSelection : unable to get object" );
392 return;
393 }
394
395 if ( object->dataType() == DATA_TRIANGLE_MESH ) {
397 } else if ( object->dataType() == DATA_POLY_MESH ) {
399 } else {
400 emit log(LOGERR,"colorizeEdgeSelection : Unsupported object Type" );
401 return;
402 }
403
404 emit scriptInfo( "colorizeEdgeSelection( ObjectId(" + QString::number(objectId) + "), "
405 + QString::number(r) + ", " + QString::number(g) + ", " + QString::number(b) + " )" );
406
407 emit updatedObject(object->id(), UPDATE_COLOR);
408}
409
410namespace {
411
412template<class MeshT>
413inline bool edgeSelected(MeshT &mesh, typename MeshT::HalfedgeHandle he) {
414 return mesh.status(mesh.edge_handle(he)).selected();
415}
416template<class MeshT>
417void traceEdgePath(MeshT &mesh, double threshold) {
418 typedef typename MeshT::HalfedgeHandle HEH;
419
420 for (auto he_it : mesh.halfedges()) {
421 if (edgeSelected(mesh, he_it)) {
422
423 OpenMesh::SmartHalfedgeHandle current_he = he_it;
424
425 for (bool tracing = true; tracing;) {
426 const typename MeshT::Normal cur_vec = mesh.calc_edge_vector(current_he).normalized();
427 const HEH back_out_he = current_he.opp();
429 double best_alignment = -std::numeric_limits<double>::infinity();
430 const typename OpenMesh::SmartVertexHandle to_vtx = current_he.to();
431
432 for (auto voh_it : to_vtx.outgoing_halfedges()) {
433 if (voh_it == back_out_he) continue;
434 if (edgeSelected(mesh, voh_it)) {
435 tracing = false;
436 break;
437 }
438 const typename MeshT::Normal next_vec = mesh.calc_edge_vector(voh_it).normalized();
439 if (best_alignment < (cur_vec | next_vec)) {
440 best_alignment = (cur_vec | next_vec);
441 best_out_he = voh_it;
442 }
443 }
444 if (tracing && best_alignment > threshold) {
445 current_he = best_out_he;
446 mesh.status(current_he.edge()).set_selected(true);
447 } else {
448 tracing = false;
449 }
450 }
451 }
452 }
453}
454}
455
456void MeshObjectSelectionPlugin::traceEdgePath(int objectId, double threshold) {
457 BaseObjectData* object;
458 if ( ! PluginFunctions::getObject(objectId,object) ) {
459 emit log(LOGERR,"traceEdgePath: unable to get object" );
460 return;
461 }
462
463 if ( object->dataType() == DATA_TRIANGLE_MESH ) {
464 ::traceEdgePath(*PluginFunctions::triMesh(object), threshold);
465 } else if ( object->dataType() == DATA_POLY_MESH ) {
466 ::traceEdgePath(*PluginFunctions::polyMesh(object), threshold);
467 } else {
468 emit log(LOGERR,"traceEdgePath: Unsupported object Type" );
469 return;
470 }
471
472 emit scriptInfo(QString::fromUtf8("traceEdgePath(ObjectId(%1), %2)")
473 .arg(objectId).arg(threshold));
474
475 emit updatedObject(object->id(), UPDATE_SELECTION_EDGES);
476}
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:181
@ LOGERR
Functions for selection on a mesh.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
bool dataType(DataType _type) const
Definition: BaseObject.cc:219
int id() const
Definition: BaseObject.cc:188
void colorizeSelection(MeshT *_mesh, PrimitiveType _primitiveTypes, int _red, int _green, int _blue, int _alpha)
Colorize the selection.
IdList convertVertexPairsToEdges(int _id, const IdList &_vertices)
Inverse of function above.
void createMeshFromSelection(MeshT &_mesh, MeshT &_newMesh, PrimitiveType _primitiveType)
Create a new mesh from the selection.
void unselectEdges(int objectId, IdList _edgeList)
Unselect given Edges.
IdList getEdgeSelection(int objectId)
Return a list of all selected edges.
bool selectElement(int _objectId, HandleT _handle, bool _fly_to_element)
set dihedral angle threshold for edge selection
void invertEdgeSelection(int objectId)
Unselect all Edges.
int createMeshFromEdgeSelection(int _objectId)
Create a mesh containing the face selection of the given mesh.
void selectEdges(int objectId, IdList _edgeList, const double _dihedral_angle_threshold=0.0)
Select given Edges.
bool selectEdge(int _objectId, int _idx, bool _fly_to_edge)
Select edge with id _idx and maybe fly to it.
void selectAllEdges(int objectId)
Select all Edges.
void clearEdgeSelection(int objectId)
Invert the current edge selection.
void traceEdgePath(int objectId, double threshold)
Trace Edge Path.
SelectionInterface::PrimitiveType edgeType_
Handle to selection environment.
void selectBoundaryEdges(int objectId)
select boundary edges
void update_dihedral_angle_threshold_from_ui()
set dihedral angle threshold for edge selection
bool deleteSelection(MeshT *_mesh, PrimitiveType _primitiveType)
Delete all selected elements of a mesh.
void colorizeEdgeSelection(int objectId, int r, int g, int b, int a)
Colorize the edge selection.
IdList convertEdgesToVertexPairs(int _id, const IdList &_edges)
Convert edge ids to vertex pairs.
void deleteEdgeSelection(int _objectId)
Delete edges that are currently selected.
MeshT * mesh()
return a pointer to the mesh
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
Kernel::EdgeHandle EdgeHandle
Scalar type.
Definition: PolyMeshT.hh:138
void calc_edge_vector(EdgeHandle _eh, Normal &_edge_vec) const
Definition: PolyMeshT.hh:406
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
const UpdateType UPDATE_SELECTION_EDGES(UpdateTypeSet(64))
Edge selection has changed.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const UpdateType UPDATE_COLOR(UpdateTypeSet(1024))
Colors have changed.
SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity *_mesh)
Creats a SmartVertexHandle from a VertexHandle and a Mesh.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Handle for a edge entity.
Definition: Handles.hh:135
SmartEdgeHandle edge() const
Returns incident edge of halfedge.
SmartHalfedgeHandle opp() const
Returns opposite halfedge handle.
SmartVertexHandle to() const
Returns vertex pointed to by halfedge.
Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...
PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges() const
Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range())