Просмотр исходного кода

decimation

Former-commit-id: f8919afb40fe2f3e07169334b16e66286bd50946
Alec Jacobson 10 лет назад
Родитель
Сommit
1a89ca9dd6
2 измененных файлов с 245 добавлено и 0 удалено
  1. 164 0
      include/igl/decimate.cpp
  2. 81 0
      include/igl/decimate.h

+ 164 - 0
include/igl/decimate.cpp

@@ -0,0 +1,164 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "decimate.h"
+#include "collapse_edge.h"
+#include "edge_flaps.h"
+#include "remove_unreferenced.h"
+#include <iostream>
+
+IGL_INLINE bool igl::decimate(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const size_t max_m,
+  Eigen::MatrixXd & U,
+  Eigen::MatrixXi & G)
+{
+  const auto & max_m_faces = 
+    [&max_m,&F](
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const std::set<std::pair<double,int> > &,
+    const std::vector<std::set<std::pair<double,int> >::iterator > &,
+    const Eigen::MatrixXd &,
+    const int,
+    const int,
+    const int,
+    const int,
+    const int)->bool
+    {
+      using namespace std;
+      static int m = F.rows();
+      m-=2;
+      return m<=(int)max_m;
+    };
+  const auto & shortest_edge_and_midpoint = [](
+    const int e,
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & /*F*/,
+    const Eigen::MatrixXi & E,
+    const Eigen::VectorXi & /*EMAP*/,
+    const Eigen::MatrixXi & /*EF*/,
+    const Eigen::MatrixXi & /*EI*/,
+    double & cost,
+    Eigen::RowVectorXd & p)
+  {
+    cost = (V.row(E(e,0))-V.row(E(e,1))).norm();
+    p = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
+  };
+  return decimate(V,F,shortest_edge_and_midpoint,max_m_faces,U,G);
+}
+
+IGL_INLINE bool igl::decimate(
+  const Eigen::MatrixXd & OV,
+  const Eigen::MatrixXi & OF,
+  const std::function<void(
+    const int,
+    const Eigen::MatrixXd &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::VectorXi &,
+    const Eigen::MatrixXi &,
+    const Eigen::MatrixXi &,
+    double &,
+    Eigen::RowVectorXd &)> & cost_and_placement,
+  const std::function<bool(
+      const Eigen::MatrixXd &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::VectorXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const std::set<std::pair<double,int> > &,
+      const std::vector<std::set<std::pair<double,int> >::iterator > &,
+      const Eigen::MatrixXd &,
+      const int,
+      const int,
+      const int,
+      const int,
+      const int)> & stopping_condition,
+  Eigen::MatrixXd & U,
+  Eigen::MatrixXi & G)
+{
+  using namespace Eigen;
+  using namespace std;
+  // Working copies
+  Eigen::MatrixXd V = OV;
+  Eigen::MatrixXi F = OF;
+  VectorXi EMAP;
+  MatrixXi E,EF,EI;
+  typedef std::set<std::pair<double,int> > PriorityQueue;
+  PriorityQueue Q;
+  std::vector<PriorityQueue::iterator > Qit;
+  edge_flaps(F,E,EMAP,EF,EI);
+  Qit.resize(E.rows());
+  // If an edge were collapsed, we'd collapse it to these points:
+  MatrixXd C(E.rows(),V.cols());
+  for(int e = 0;e<E.rows();e++)
+  {
+    double cost = e;
+    RowVectorXd p(1,3);
+    cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
+    C.row(e) = p;
+    Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
+  }
+
+  int prev_e = -1;
+  bool clean_finish = false;
+  while(true)
+  {
+    if(Q.empty())
+    {
+      break;
+    }
+    if(Q.begin()->first == std::numeric_limits<double>::infinity())
+    {
+      // min cost edge is infinite cost
+      break;
+    }
+    int e,e1,e2,f1,f2;
+    if(collapse_edge(cost_and_placement,V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
+    {
+      if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
+      {
+        clean_finish = true;
+        break;
+      }
+    }else
+    {
+      if(prev_e == e)
+      {
+        assert(false && "Edge collapse no progress... bad stopping condition?");
+        break;
+      }
+      // Edge was not collapsed... must have been invalid. collapse_edge should
+      // have updated its cost to inf... continue
+    }
+    prev_e = e;
+  }
+  // remove all IGL_COLLAPSE_EDGE_NULL faces
+  MatrixXi F2(F.rows(),3);
+  int m = 0;
+  for(int f = 0;f<F.rows();f++)
+  {
+    if(
+      F(f,0) != IGL_COLLAPSE_EDGE_NULL || 
+      F(f,1) != IGL_COLLAPSE_EDGE_NULL || 
+      F(f,2) != IGL_COLLAPSE_EDGE_NULL)
+    {
+      F2.row(m++) = F.row(f);
+    }
+  }
+  F2.conservativeResize(m,F2.cols());
+  VectorXi _1;
+  remove_unreferenced(V,F2,U,G,_1);
+  return clean_finish;
+}

+ 81 - 0
include/igl/decimate.h

@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DECIMATE_H
+#define IGL_DECIMATE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+namespace igl
+{
+  // Assumes (V,F) is a closed manifold mesh 
+  // Collapses edges until desired number of faces is achieved. This uses
+  // default edge cost and merged vertex placement functions {edge length, edge
+  // midpoint}.
+  //
+  // Inputs:
+  //   V  #V by dim list of vertex positions
+  //   F  #F by 3 list of face indices into V.
+  //   max_m  desired number of output faces
+  // Outputs:
+  //   U  #U by dim list of output vertex posistions (can be same ref as V)
+  //   G  #G by 3 list of output face indices into U (can be same ref as G)
+  // Returns true if m was reached (otherwise #G > m)
+  IGL_INLINE bool decimate(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const size_t max_m,
+    Eigen::MatrixXd & U,
+    Eigen::MatrixXi & G);
+  // Inputs:
+  //   cost_and_placement  function computing cost of collapsing an edge and 3d
+  //     position where it should be placed:
+  //     cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
+  //   stopping_condition  function returning whether to stop collapsing edges
+  //     based on current state. Guaranteed to be called after _successfully_
+  //     collapsing edge e removing edges (e,e1,e2) and faces (f1,f2):
+  //     bool should_stop =
+  //       stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
+  IGL_INLINE bool decimate(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const std::function<void(
+      const int,
+      const Eigen::MatrixXd &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::VectorXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      double &,
+      Eigen::RowVectorXd &)> & cost_and_placement,
+    const std::function<bool(
+      const Eigen::MatrixXd &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::VectorXi &,
+      const Eigen::MatrixXi &,
+      const Eigen::MatrixXi &,
+      const std::set<std::pair<double,int> > &,
+      const std::vector<std::set<std::pair<double,int> >::iterator > &,
+      const Eigen::MatrixXd &,
+      const int,
+      const int,
+      const int,
+      const int,
+      const int)> & stopping_condition,
+    Eigen::MatrixXd & U,
+    Eigen::MatrixXi & G);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "decimate.cpp"
+#endif
+#endif
+