Jelajahi Sumber

wire mesh

Former-commit-id: ea866463d8200780a127518c58b28741843bd3f9
Alec Jacobson 8 tahun lalu
induk
melakukan
5d4d89fb1f
2 mengubah file dengan 228 tambahan dan 0 penghapusan
  1. 180 0
      include/igl/copyleft/cgal/wire_mesh.cpp
  2. 48 0
      include/igl/copyleft/cgal/wire_mesh.h

+ 180 - 0
include/igl/copyleft/cgal/wire_mesh.cpp

@@ -0,0 +1,180 @@
+#include "wire_mesh.h"
+
+#include "../../list_to_matrix.h"
+#include "../../slice.h"
+#include "convex_hull.h"
+#include "mesh_boolean.h"
+#include <Eigen/Geometry>
+#include <vector>
+
+template <
+  typename DerivedWV,
+  typename DerivedWE,
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::wire_mesh(
+  const Eigen::MatrixBase<DerivedWV> & WV,
+  const Eigen::MatrixBase<DerivedWE> & WE,
+  const double th,
+  const int poly_size,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedJ> & J)
+{
+
+  typedef typename DerivedWV::Scalar Scalar;
+  // Canonical polygon to place at each endpoint
+  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
+  MatrixX3S PV(poly_size,3);
+  for(int p =0;p<PV.rows();p++)
+  {
+    const Scalar phi = (Scalar(p)/Scalar(PV.rows()))*2.*M_PI;
+    PV(p,0) = 0.5*cos(phi);
+    PV(p,1) = 0.5*sin(phi);
+    PV(p,2) = 0;
+  }
+
+  V.resize(WV.rows() + PV.rows() * 2 * WE.rows(),3);
+  V.topLeftCorner(WV.rows(),3) = WV;
+  // Signed adjacency list
+  std::vector<std::vector<std::pair<int,int> > > A(WV.rows());
+  // Inputs:
+  //   e  index of edge
+  //   c  index of endpoint [0,1]
+  //   p  index of polygon vertex
+  // Returns index of corresponding vertex in V
+  const auto index = 
+    [&PV,&WV](const int e, const int c, const int p)->int
+  {
+    return WV.rows() + e*2*PV.rows() + PV.rows()*c + p;
+  };
+  const auto unindex = 
+    [&PV,&WV](int v, int & e, int & c, int & p)
+  {
+    assert(v>=WV.rows());
+    v = v-WV.rows();
+    e = v/(2*PV.rows());
+    v = v-e*(2*PV.rows());
+    c = v/(PV.rows());
+    v = v-c*(PV.rows());
+    p = v;
+  };
+  // loop over all edges
+  for(int e = 0;e<WE.rows();e++)
+  {
+    // Fill in adjacency list as we go
+    A[WE(e,0)].emplace_back(e,0);
+    A[WE(e,1)].emplace_back(e,1);
+    typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+    const RowVector3S ev = WV.row(WE(e,1))-WV.row(WE(e,0));
+    const RowVector3S uv = ev.normalized();
+    Eigen::Quaternion<Scalar> q;
+    q = q.FromTwoVectors(RowVector3S(0,0,1),uv);
+    // loop over polygon vertices
+    for(int p = 0;p<PV.rows();p++)
+    {
+      RowVector3S qp = q*(PV.row(p)*th);
+      // loop over endpoints
+      for(int c = 0;c<2;c++)
+      {
+        // Move to endpoint, offset by factor of thickness
+        V.row(index(e,c,p)) = 
+          qp+WV.row(WE(e,c)) + 1.*th*Scalar(1-2*c)*uv;
+      }
+    }
+  }
+
+  std::vector<std::vector<typename DerivedF::Index> > vF;
+  std::vector<int> vJ;
+  const auto append_hull = 
+    [&V,&vF,&vJ,&unindex,&WV](const Eigen::VectorXi & I, const int j)
+  {
+    MatrixX3S Vv;
+    igl::slice(V,I,1,Vv);
+    Eigen::MatrixXi Fv;
+    convex_hull(Vv,Fv);
+    for(int f = 0;f<Fv.rows();f++)
+    {
+      const Eigen::Array<int,1,3> face(I(Fv(f,0)), I(Fv(f,1)), I(Fv(f,2)));
+      //const bool on_vertex = (face<WV.rows()).any();
+      //if(!on_vertex)
+      //{
+      //  // This correctly prunes fcaes on the "caps" of convex hulls around
+      //  // edges, but for convex hulls around vertices this will only work if
+      //  // the incoming edges are not overlapping.
+      //  //
+      //  // Q: For convex hulls around vertices, is the correct thing to do:
+      //  // check if all corners of face lie *on or _outside_* of plane of "cap"?
+      //  // 
+      //  // H: Maybe, but if there's an intersection then the boundary of the
+      //  // incoming convex hulls around edges is still not going to match up
+      //  // with the boundary on the convex hull around the vertices.
+      //  //
+      //  // Might have to bite the bullet and always call self-union.
+      //  bool all_same = true;
+      //  int e0,c0,p0;
+      //  unindex(face(0),e0,c0,p0);
+      //  for(int i = 1;i<3;i++)
+      //  {
+      //    int ei,ci,pi;
+      //    unindex(face(i),ei,ci,pi);
+      //    all_same = all_same && (e0==ei && c0==ci);
+      //  }
+      //  if(all_same)
+      //  {
+      //    // don't add this face
+      //    continue;
+      //  }
+      //}
+      vF.push_back( { face(0),face(1),face(2)});
+      vJ.push_back(j);
+    }
+  };
+  // loop over each vertex
+  for(int v = 0;v<WV.rows();v++)
+  {
+    // Gather together this vertex and the polygon vertices of all incident
+    // edges
+    Eigen::VectorXi I(1+A[v].size()*PV.rows());
+    // This vertex
+    I(0) = v;
+    for(int n = 0;n<A[v].size();n++)
+    {
+      for(int p = 0;p<PV.rows();p++)
+      {
+        const int e = A[v][n].first;
+        const int c = A[v][n].second;
+        I(1+n*PV.rows()+p) = index(e,c,p);
+      }
+    }
+    append_hull(I,v);
+  }
+  // loop over each edge
+  for(int e = 0;e<WE.rows();e++)
+  {
+    // Gether together polygon vertices of both endpoints
+    Eigen::VectorXi I(PV.rows()*2);
+    for(int c = 0;c<2;c++)
+    {
+      for(int p = 0;p<PV.rows();p++)
+      {
+        I(c*PV.rows()+p) = index(e,c,p);
+      }
+    }
+    append_hull(I,WV.rows()+e);
+  }
+
+  list_to_matrix(vF,F);
+  // Self-union to clean up 
+  igl::copyleft::cgal::mesh_boolean(
+    Eigen::MatrixXd(V),Eigen::MatrixXi(F),Eigen::MatrixXd(),Eigen::MatrixXi(),
+    "union",
+    V,F,J);
+  for(int j=0;j<J.size();j++) J(j) = vJ[J(j)];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation 
+template void igl::copyleft::cgal::wire_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif

+ 48 - 0
include/igl/copyleft/cgal/wire_mesh.h

@@ -0,0 +1,48 @@
+#ifndef IGL_COPYLEFT_CGAL_WIRE_MESH_H
+#define IGL_COPYLEFT_CGAL_WIRE_MESH_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  namespace copyleft
+  {
+    // Construct a "wire" or "wireframe" or "strut" surface mesh, given a
+    // one-dimensional network of straight edges.
+    //
+    // Inputs:
+    //   WV  #WV by 3 list of vertex positions
+    //   WE  #WE by 2 list of edge indices into WV
+    //   th  diameter thickness of wire 
+    //   poly_size  number of sides on each wire (e.g., 4 would produce wires by
+    //     connecting rectangular prisms).
+    // Outputs:
+    //   V  #V by 3 list of output vertices
+    //   F  #F by 3 list of output triangle indices into V
+    //   J  #F list of indices into [0,#WV+#WE) revealing "birth simplex" of
+    //     output faces J(j) < #WV means the face corresponds to the J(j)th
+    //     vertex in WV. J(j) >= #WV means the face corresponds to the
+    //     (J(j)-#WV)th edge in WE.
+    namespace cgal
+    {
+      template <
+        typename DerivedWV,
+        typename DerivedWE,
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedJ>
+      IGL_INLINE void wire_mesh(
+        const Eigen::MatrixBase<DerivedWV> & WV,
+        const Eigen::MatrixBase<DerivedWE> & WE,
+        const double th,
+        const int poly_size,
+        Eigen::PlainObjectBase<DerivedV> & V,
+        Eigen::PlainObjectBase<DerivedF> & F,
+        Eigen::PlainObjectBase<DerivedJ> & J);
+    }
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "wire_mesh.cpp"
+#endif
+#endif