Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
1 result

EdgeFunctions.cc

Blame
  • 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) + ".");
    }
    
    
    //-----------------------------------------------------------------------------