Select Git revision
EdgeFunctions.cc
-
Daniel Savchenko authoredDaniel Savchenko authored
EdgeFunctions.cc 11.26 KiB
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (c) 2001-2015, RWTH-Aachen University *
* Department of Computer Graphics and Multimedia *
* All rights reserved. *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
*---------------------------------------------------------------------------*
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
\*===========================================================================*/
#include "MeshRepairPlugin.hh"
#include <MeshTools/MeshSelectionT.hh>
//-----------------------------------------------------------------------------
void MeshRepairPlugin::selectEdgesShorterThan(int _objectId,double _length) {
selectionEdgeLength(_objectId,_length,false);
emit scriptInfo( "selectEdgesShorterThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::selectEdgesLongerThan(int _objectId,double _length) {
selectionEdgeLength(_objectId,_length,true);
emit scriptInfo( "selectEdgesLongerThan(" + QString::number(_objectId) + ", " + QString::number(_length) + ")" );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::selectionEdgeLength(int _objectId, double _length, bool _larger) {
// get the target mesh
TriMesh* triMesh = 0;
PluginFunctions::getMesh(_objectId,triMesh);
if ( triMesh ) {
// Clear current edge selection
MeshSelection::clearEdgeSelection(triMesh);
// Iterate over all edges
for (auto e_it : triMesh->edges()) {
OpenMesh::SmartHalfedgeHandle he = e_it.h0();
TriMesh::Point p1 = triMesh->point( he.from() );
TriMesh::Point p2 = triMesh->point( he.to() );
if ( _larger ) {
if ( (p1 - p2).norm() > _length)
triMesh->status(e_it).set_selected(true);
} else {
if ( (p1 - p2).norm() < _length)
triMesh->status(e_it).set_selected(true);
}
}
emit updatedObject(_objectId,UPDATE_SELECTION);
emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
return;
}
// get the target mesh
PolyMesh* polyMesh = 0;
PluginFunctions::getMesh(_objectId,polyMesh);
if ( polyMesh ) {
// Clear current edge selection
MeshSelection::clearEdgeSelection(polyMesh);
// Iterate over all edges
for (auto e_it : polyMesh->edges()) {
OpenMesh::SmartHalfedgeHandle he = e_it.h0();
PolyMesh::Point p1 = polyMesh->point( he.from() );
PolyMesh::Point p2 = polyMesh->point( he.to() );
if ( _larger ) {
if ( (p1 - p2).norm() > _length)
polyMesh->status(e_it).set_selected(true);
} else {
if ( (p1 - p2).norm() < _length)
polyMesh->status(e_it).set_selected(true);
}
}
emit updatedObject(_objectId,UPDATE_SELECTION);
emit createBackup( _objectId, "Select Edges", UPDATE_SELECTION);
return;
}
emit log( LOGERR,tr("Unsupported Object Type for edge selection") );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::removeSelectedEdges(int _objectId) {
// get the target mesh
TriMesh* triMesh = 0;
PluginFunctions::getMesh(_objectId, triMesh);
if (triMesh) {
for (auto e_it : triMesh->edges()) {
if (!triMesh->status(e_it).deleted() && triMesh->status(e_it).selected()) {
const OpenMesh::SmartVertexHandle v0 = e_it.h0().to();
const OpenMesh::SmartVertexHandle v1 = e_it.h1().to();
const bool boundary0 = v0.is_boundary();
const bool boundary1 = v1.is_boundary();
const bool feature0 = triMesh->status(v0).feature();
const bool feature1 = triMesh->status(v1).feature();
const bool featureE = triMesh->status(e_it).feature();
// Collapsing v1 into vo:
// collapse is ok, if collapsed vertex is not a feature vertex or the target vertex is a feature
// and if we collapse along an feature edge or if the collapsed vertex is not a feature
if ((!boundary1 || boundary0) && (!feature1 || (feature0 && featureE)) && triMesh->is_collapse_ok(
e_it.h0()))
triMesh->collapse(e_it.h0());
else if ((!boundary0 || boundary1) && (!feature0 || (feature1 && featureE)) && triMesh->is_collapse_ok(
e_it.h1()))
triMesh->collapse(e_it.h1());
}
}
triMesh->garbage_collection();
triMesh->update_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, "Removed selected Edges", UPDATE_ALL);
emit scriptInfo("removeSelectedEdges(" + QString::number(_objectId) + ")");
return;
}
emit log(LOGERR, tr("Unsupported Object Type for edge removal"));
}
void MeshRepairPlugin::detectSkinnyTriangleByAngle(int _objectId, double _angle, bool _remove) {
// get the target mesh
TriMesh* triMesh = 0;
PluginFunctions::getMesh(_objectId, triMesh);
if (triMesh) {
// Clear current edge selection
MeshSelection::clearEdgeSelection(triMesh);
double maxAngle = cos(_angle * M_PI / 180.0);
double angle = 0.0;
for (auto e_it : triMesh->edges()) {
// Check prerequisites
if (!triMesh->status(e_it).deleted() && !triMesh->status(e_it).feature() && triMesh->is_flip_ok(e_it)) {
// For both halfedges
for (unsigned int h = 0; h < 2; ++h) {
TriMesh::HalfedgeHandle hh = triMesh->halfedge_handle(e_it, h);
const TriMesh::Point& a = triMesh->point(triMesh->from_vertex_handle(hh));
const TriMesh::Point& b = triMesh->point(triMesh->to_vertex_handle(hh));
hh = triMesh->next_halfedge_handle(hh);
const TriMesh::Point& c = triMesh->point(triMesh->to_vertex_handle(hh));
const double angle = ((a - c).normalize() | (b - c).normalize());
if (angle < maxAngle) {
// selcet it
triMesh->status(e_it).set_selected(true);
// remove it if requested
if (_remove)
triMesh->flip(e_it);
}
}
}
}
if (_remove) {
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, tr("Removed cap edges"), UPDATE_ALL);
} else {
emit updatedObject(_objectId, UPDATE_SELECTION);
emit createBackup(_objectId, tr("Selected cap edges"), UPDATE_ALL);
} emit
scriptInfo(
"detectSkinnyTriangleByAngle(" + QString::number(_objectId) + "," + QString::number(_angle) + ","
+ (_remove?"TRUE":"FALSE") + ")");
return;
}
emit log(LOGERR, tr("Unsupported Object Type for Cap detection!"));
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::detectFoldover(int _objectId, float _angle) {
// get the target mesh
TriMeshObject* trimesh_o = 0;
PolyMeshObject* polymesh_o = 0;
PluginFunctions::getObject(_objectId, trimesh_o);
PluginFunctions::getObject(_objectId, polymesh_o);
unsigned int count = 0;
if (trimesh_o != 0) {
// get the target mesh
TriMesh* mesh = trimesh_o->mesh();
if (mesh) {
// Clear current edge selection
MeshSelection::clearEdgeSelection(mesh);
TriMesh::FaceHandle fh;
TriMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
for (auto e_it : mesh->edges()) {
if (!e_it.is_boundary()) {
a = (mesh->normal(e_it.h0().face()) | mesh->normal(
e_it.h1().face()));
if (a < cosa) {
mesh->status(e_it.h0().edge()). set_selected(true);
++count;
}
}
}
}
} else if (polymesh_o != 0) {
// get the target mesh
PolyMesh* mesh = polymesh_o->mesh();
if (mesh) {
// Clear current edge selection
MeshSelection::clearEdgeSelection(mesh);
PolyMesh::FaceHandle fh;
PolyMesh::Scalar a, cosa = cos(_angle / 180.0 * M_PI);
for (auto e_it : mesh->edges()) {
if (!e_it.is_boundary()) {
a = (mesh->normal(e_it.h0().face()) | mesh->normal(
e_it.h1().face()));
if (a < cosa) {
mesh->status(e_it.h0().edge()). set_selected(true);
++count;
}
}
}
}
}
if (count > 0) {
emit updatedObject(_objectId, UPDATE_SELECTION);
emit createBackup(_objectId, "Select edges", UPDATE_SELECTION);
emit scriptInfo("detectFoldover(" + QString::number(_objectId) + ", " + QString::number(_angle) + ")");
}
emit log(
"Selected " + QString::number(count) + " fold-overs on object " + QString::number(_objectId)
+ " with angle greater than " + QString::number(_angle) + ".");
}
//-----------------------------------------------------------------------------