Prechádzať zdrojové kódy

convert list of edges forming chain/loop into path

Former-commit-id: 8b1c4f6a55bbc72d72dab74ec95ee10730a4082c
Alec Jacobson 8 rokov pred
rodič
commit
236b440c34

+ 48 - 0
include/igl/dfs.h

@@ -0,0 +1,48 @@
+#ifndef IGL_DFS_H
+#define IGL_DFS_H
+#include "igl_inline.h"
+#include <vector>
+namespace igl
+{
+  // Traverse a **directed** graph represented by an adjacency list using
+  // depth first search
+  //
+  // Inputs:
+  //   A  #V list of adjacency lists
+  //   s  starting node (index into A)
+  // Outputs:
+  //   D  #V list of indices into rows of A in the order in which graph nodes
+  //     are discovered.
+  //   P  #V list of indices into rows of A of predecessor in resulting
+  //     spanning tree {-1 indicates root/not discovered), order corresponds to
+  //     V **not** D.
+  //   C  #V list of indices into rows of A in order that nodes are "closed"
+  //     (all descendants have been discovered)
+  template <
+    typename AType,
+    typename DerivedD,
+    typename DerivedP,
+    typename DerivedC>
+  IGL_INLINE void dfs(
+    const std::vector<std::vector<AType> > & A,
+    const size_t s,
+    Eigen::PlainObjectBase<DerivedD> & D,
+    Eigen::PlainObjectBase<DerivedP> & P,
+    Eigen::PlainObjectBase<DerivedC> & C);
+  template <
+    typename AType,
+    typename DType,
+    typename PType,
+    typename CType>
+  IGL_INLINE void dfs(
+    const std::vector<std::vector<AType> > & A,
+    const size_t s,
+    std::vector<DType> & D,
+    std::vector<PType> & P,
+    std::vector<CType> & C);
+
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "dfs.cpp"
+#endif
+#endif

+ 93 - 0
include/igl/edges_to_path.cpp

@@ -0,0 +1,93 @@
+#include "edges_to_path.h"
+#include "ismember.h"
+#include "adjacency_matrix.h"
+
+template <
+  typename DerivedE,
+  typename DerivedI,
+  typename DerivedJ,
+  typename DerivedK>
+IGL_INLINE void igl::edges_to_path(
+  const Eigen::MatrixBase<DerivedE> & OE,
+  Eigen::PlainObjectBase<DerivedI> & I,
+  Eigen::PlainObjectBase<DerivedJ> & J,
+  Eigen::PlainObjectBase<DerivedK> & K)
+{
+  assert(OE.rows()>=1);
+  if(OE.rows() == 1)
+  {
+    I.resize(2);
+    I(0) = OE(0);
+    I(1) = OE(1);
+    J.resize(1);
+    J(0) = 0;
+    K.resize(1);
+    K(0) = 0;
+  }
+
+  // Compute on reduced graph
+  DerivedI U;
+  DerivedE E;
+  {
+    Eigen::VectorXi IA;
+    unique(OE,U,IA,E);
+  }
+
+  Eigen::VectorXi V = Eigen::VectorXi::Zero(E.maxCoeff()+1);
+  for(int e = 0;e<E.size();e++)
+  {
+    V(E(e))++;
+    assert(V(E(e))<=2);
+  }
+  // Try to find a vertex with valence = 1
+  int c = 2;
+  int s = E(0);
+  for(int v = 0;v<V.size();v++)
+  {
+    if(V(v) == 1)
+    {
+      c = V(v);
+      s = v;
+      break;
+    }
+  }
+  assert(V(s) == c);
+  assert(c == 2 || c == 1);
+
+  // reshape E to be #E by 2
+  E = Eigen::Map<DerivedE>(E.data(),OE.rows(),OE.cols()).eval();
+  {
+    std::vector<std::vector<int> > A;
+    igl::adjacency_list(E,A);
+    Eigen::VectorXi P,C;
+    dfs(A,s,I,P,C);
+  }
+  if(c == 2)
+  {
+    I.conservativeResize(I.size()+1);
+    I(I.size()-1) = I(I.size()-2);
+  }
+
+  DerivedE sE;
+  Eigen::Matrix<typename DerivedI::Scalar,Eigen::Dynamic,2> sEI;
+  {
+    Eigen::MatrixXi _;
+    sort(E,2,true,sE,_);
+    Eigen::Matrix<typename DerivedI::Scalar,Eigen::Dynamic,2> EI(I.size()-1,2);
+    EI.col(0) = I.head(I.size()-1);
+    EI.col(1) = I.tail(I.size()-1);
+    sort(EI,2,true,sEI,_);
+  }
+  {
+    Eigen::Array<bool,Eigen::Dynamic,1> F;
+    ismember_rows(sEI,sE,F,J);
+  }
+  K.resize(I.size()-1);
+  for(int k = 0;k<K.size();k++)
+  {
+    K(k) = 1 + (E(J(k),0) != I(k) ? 1 : 0);
+  }
+
+  // Map vertex indices onto original graph
+  slice(U,DerivedI(I),1,I);
+}

+ 36 - 0
include/igl/edges_to_path.h

@@ -0,0 +1,36 @@
+#ifndef IGL_EDGES_TO_PATH_H
+#define IGL_EDGES_TO_PATH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // EDGES_TO_PATH Given a set of undirected, unique edges such that all form a
+  // single connected compoent with exactly 0 or 2 nodes with valence =1,
+  // determine the/a path visiting all nodes.
+  //
+  // Inputs:
+  //   E  #E by 2 list of undirected edges
+  // Outputs:
+  //   I  #E+1 list of nodes in order tracing the chain (loop), if the output
+  //     is a loop then I(1) == I(end)
+  //   J  #I-1 list of indices into E of edges tracing I
+  //   K  #I-1 list of indices into columns of E {1,2} so that K(i) means that
+  //     E(i,K(i)) comes before the other (i.e., E(i,3-K(i)) ). This means that 
+  //     I(i) == E(J(i),K(i)) for i<#I, or
+  //     I == E(sub2ind(size(E),J([1:end end]),[K;3-K(end)]))))
+  // 
+  template <
+    typename DerivedE,
+    typename DerivedI,
+    typename DerivedJ,
+    typename DerivedK>
+  IGL_INLINE void edges_to_path(
+    const Eigen::MatrixBase<DerivedE> & E,
+    Eigen::PlainObjectBase<DerivedI> & I,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::PlainObjectBase<DerivedK> & K);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "edges_to_path.cpp"
+#endif
+#endif