Esempio n. 1
0
IGL_INLINE void igl::adjacency_matrix(
  const Eigen::PlainObjectBase<DerivedF> & F, 
  Eigen::SparseMatrix<T>& A)
{
  using namespace std;
  using namespace Eigen;
  typedef typename DerivedF::Scalar Index;

  typedef Triplet<T> IJV;
  vector<IJV > ijv;
  ijv.reserve(F.size()*2);
  // Loop over faces
  for(int i = 0;i<F.rows();i++)
  {
    // Loop over this face
    for(int j = 0;j<F.cols();j++)
    {
      // Get indices of edge: s --> d
      Index s = F(i,j);
      Index d = F(i,(j+1)%F.cols());
      ijv.push_back(IJV(s,d,1));
      ijv.push_back(IJV(d,s,1));
    }
  }

  const Index n = F.maxCoeff()+1;
  A.resize(n,n);
  switch(F.cols())
  {
    case 3:
      A.reserve(6*(F.maxCoeff()+1));
      break;
    case 4:
      A.reserve(26*(F.maxCoeff()+1));
      break;
  }
  A.setFromTriplets(ijv.begin(),ijv.end());

  // Force all non-zeros to be one

  // Iterate over outside
  for(int k=0; k<A.outerSize(); ++k)
  {
    // Iterate over inside
    for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
    {
      assert(it.value() != 0);
      A.coeffRef(it.row(),it.col()) = 1;
    }
  }
}
IGL_INLINE std::vector<bool> igl::is_irregular_vertex(const Eigen::PlainObjectBase<DerivedV> &V, const Eigen::PlainObjectBase<DerivedF> &F)
{
  Eigen::VectorXi count = Eigen::VectorXi::Zero(F.maxCoeff());

  for(unsigned i=0; i<F.rows();++i)
  {
    for(unsigned j=0; j<F.cols();++j)
    {
      if (F(i,j) < F(i,(j+1)%F.cols())) // avoid duplicate edges
      {
        count(F(i,j  )) += 1;
        count(F(i,(j+1)%F.cols())) += 1;
      }
    }
  }

  std::vector<bool> border = is_border_vertex(V,F);

  std::vector<bool> res(count.size());

  for (unsigned i=0; i<res.size(); ++i)
    res[i] = !border[i] && count[i] != (F.cols() == 3 ? 6 : 4 );

  return res;
}
Esempio n. 3
0
IGL_INLINE void igl::jet(
  const Eigen::PlainObjectBase<DerivedZ> & Z,
  const bool normalize,
  Eigen::PlainObjectBase<DerivedC> & C)
{
  const double min_z = (normalize?Z.minCoeff():0);
  const double max_z = (normalize?Z.maxCoeff():-1);
  return jet(Z,min_z,max_z,C);
}
Esempio n. 4
0
IGL_INLINE void igl::components(
  const Eigen::SparseMatrix<AScalar> & A,
  Eigen::PlainObjectBase<DerivedC> & C,
  Eigen::PlainObjectBase<Derivedcounts> & counts)
{
  using namespace Eigen;
  using namespace std;
  assert(A.rows() == A.cols() && "A should be square.");
  const size_t n = A.rows();
  Array<bool,Dynamic,1> seen = Array<bool,Dynamic,1>::Zero(n,1);
  C.resize(n,1);
  typename DerivedC::Scalar id = 0;
  vector<typename Derivedcounts::Scalar> vcounts;
  // breadth first search
  for(int k=0; k<A.outerSize(); ++k)
  {
    if(seen(k))
    {
      continue;
    }
    queue<int> Q;
    Q.push(k);
    vcounts.push_back(0);
    while(!Q.empty())
    {
      const int f = Q.front();
      Q.pop();
      if(seen(f))
      {
        continue;
      }
      seen(f) = true;
      C(f,0) = id;
      vcounts[id]++;
      // Iterate over inside
      for(typename SparseMatrix<AScalar>::InnerIterator it (A,f); it; ++it)
      {
        const int g = it.index();
        if(!seen(g) && it.value())
        {
          Q.push(g);
        }
      }
    }
    id++;
  }
  assert((size_t) id == vcounts.size());
  const size_t ncc = vcounts.size();
  assert((size_t)C.maxCoeff()+1 == ncc);
  counts.resize(ncc,1);
  for(size_t i = 0;i<ncc;i++)
  {
    counts(i) = vcounts[i];
  }
}
IGL_INLINE void igl::directed_edge_parents(
  const Eigen::PlainObjectBase<DerivedE> & E,
  Eigen::PlainObjectBase<DerivedP> & P)
{
  using namespace Eigen;
  using namespace std;
  VectorXi I = VectorXi::Constant(E.maxCoeff()+1,1,-1);
  //I(E.col(1)) = 0:E.rows()-1
  slice_into(colon<int>(0,E.rows()-1),E.col(1).eval(),I);
  VectorXi roots,_;
  setdiff(E.col(0).eval(),E.col(1).eval(),roots,_);
  for_each(roots.data(),roots.data()+roots.size(),[&](int r){I(r)=-1;});
  slice(I,E.col(0).eval(),P);
}
IGL_INLINE void igl::slice(
  const Eigen::PlainObjectBase<DerivedX> & X,
  const Eigen::PlainObjectBase<DerivedR> & R,
  const Eigen::PlainObjectBase<DerivedC> & C,
  Eigen::PlainObjectBase<DerivedY> & Y)
{
#ifndef NDEBUG
  int xm = X.rows();
  int xn = X.cols();
#endif
  int ym = R.size();
  int yn = C.size();

  // special case when R or C is empty
  if(ym == 0 || yn == 0)
  {
    Y.resize(ym,yn);
    return;
  }

  assert(R.minCoeff() >= 0);
  assert(R.maxCoeff() < xm);
  assert(C.minCoeff() >= 0);
  assert(C.maxCoeff() < xn);

  // Resize output
  Y.resize(ym,yn);
  // loop over output rows, then columns
  for(int i = 0;i<ym;i++)
  {
    for(int j = 0;j<yn;j++)
    {
      Y(i,j) = X(R(i),C(j));
    }
  }
}
Esempio n. 7
0
IGL_INLINE void igl::cut_mesh(
                                                                  const Eigen::PlainObjectBase<DerivedV> &V,
                                                                  const Eigen::PlainObjectBase<DerivedF> &F,
                                                                  const std::vector<std::vector<VFType> >& VF,
                                                                  const std::vector<std::vector<VFType> >& VFi,
                                                                  const Eigen::PlainObjectBase<DerivedTT>& TT,
                                                                  const Eigen::PlainObjectBase<DerivedTT>& TTi,
                                                                  const std::vector<bool> &V_border,
                                                                  const Eigen::PlainObjectBase<DerivedC> &cuts,
                                                                  Eigen::PlainObjectBase<DerivedV> &Vcut,
                                                                  Eigen::PlainObjectBase<DerivedF> &Fcut)
{
  //finding the cuts is done, now we need to actually generate a cut mesh
  igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
  mc.InitMappingSeam();

  Fcut = mc.HandleS_Index;
  //we have the faces, we need the vertices;
  int newNumV = Fcut.maxCoeff()+1;
  Vcut.setZero(newNumV,3);
  for (int vi=0; vi<V.rows(); ++vi)
    for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
      Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);

  //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
  for (int fi =0; fi<Fcut.rows(); ++fi)
    for (int k=0; k<3; ++k)
      if (Fcut(fi,k)==-1)
      {
        //we need to add a vertex
        Fcut(fi,k) = newNumV;
        newNumV ++;
        Vcut.conservativeResize(newNumV, Eigen::NoChange);
        Vcut.row(newNumV-1) = V.row(F(fi,k));
      }


}
Esempio n. 8
0
IGL_INLINE void igl::gaussian_curvature(
  const Eigen::PlainObjectBase<DerivedV>& V,
  const Eigen::PlainObjectBase<DerivedF>& F,
  Eigen::PlainObjectBase<DerivedK> & K)
{
  using namespace Eigen;
  using namespace std;
  // internal corner angles
  Matrix<
    typename DerivedV::Scalar,
    DerivedF::RowsAtCompileTime,
    DerivedF::ColsAtCompileTime> A;
  internal_angles(V,F,A);
  K.resize(V.rows(),1);
  K.setConstant(V.rows(),1,2.*PI);
  assert(A.rows() == F.rows());
  assert(A.cols() == F.cols());
  assert(K.rows() == V.rows());
  assert(F.maxCoeff() < V.rows());
  assert(K.cols() == 1);
  const int Frows = F.rows();
  //K_G(x_i) = (2π - ∑θj)
//#ifndef IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE
//#  define IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE 1000
//#endif
//#pragma omp parallel for if (Frows>IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE)
  for(int f = 0;f<Frows;f++)
  {
    // throw normal at each corner
    for(int j = 0; j < 3;j++)
    {
      // Q: Does this need to be critical?
      // H: I think so, sadly. Maybe there's a way to use reduction
//#pragma omp critical
      K(F(f,j),0) -=  A(f,j);
    }
  }
}
Esempio n. 9
0
File: arap.cpp Progetto: yig/libigl
IGL_INLINE bool igl::arap_precomputation(
    const Eigen::PlainObjectBase<DerivedV> & V,
    const Eigen::PlainObjectBase<DerivedF> & F,
    const int dim,
    const Eigen::PlainObjectBase<Derivedb> & b,
    ARAPData & data)
{
    using namespace std;
    using namespace Eigen;
    typedef typename DerivedV::Scalar Scalar;
    // number of vertices
    const int n = V.rows();
    data.n = n;
    assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds");
    assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds");
    // remember b
    data.b = b;
    //assert(F.cols() == 3 && "For now only triangles");
    // dimension
    //const int dim = V.cols();
    assert((dim == 3 || dim ==2) && "dim should be 2 or 3");
    data.dim = dim;
    //assert(dim == 3 && "Only 3d supported");
    // Defaults
    data.f_ext = MatrixXd::Zero(n,data.dim);

    assert(data.dim <= V.cols() && "solve dim should be <= embedding");
    bool flat = (V.cols() - data.dim)==1;

    DerivedV plane_V;
    DerivedF plane_F;
    typedef SparseMatrix<Scalar> SparseMatrixS;
    SparseMatrixS ref_map,ref_map_dim;
    if(flat)
    {
        project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map);
        repdiag(ref_map,dim,ref_map_dim);
    }
    const PlainObjectBase<DerivedV>& ref_V = (flat?plane_V:V);
    const PlainObjectBase<DerivedF>& ref_F = (flat?plane_F:F);
    SparseMatrixS L;
    cotmatrix(V,F,L);

    ARAPEnergyType eff_energy = data.energy;
    if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT)
    {
        switch(F.cols())
        {
        case 3:
            if(data.dim == 3)
            {
                eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS;
            } else
            {
                eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
            }
            break;
        case 4:
            eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
            break;
        default:
            assert(false);
        }
    }


    // Get covariance scatter matrix, when applied collects the covariance
    // matrices used to fit rotations to during optimization
    covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM);
    if(flat)
    {
        data.CSM = (data.CSM * ref_map_dim.transpose()).eval();
    }
    assert(data.CSM.cols() == V.rows()*data.dim);

    // Get group sum scatter matrix, when applied sums all entries of the same
    // group according to G
    SparseMatrix<double> G_sum;
    if(data.G.size() == 0)
    {
        if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
        {
            speye(F.rows(),G_sum);
        } else
        {
            speye(n,G_sum);
        }
    } else
    {
        // groups are defined per vertex, convert to per face using mode
        if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
        {
            Eigen::Matrix<int,Eigen::Dynamic,1> GG;
            MatrixXi GF(F.rows(),F.cols());
            for(int j = 0; j<F.cols(); j++)
            {
                Matrix<int,Eigen::Dynamic,1> GFj;
                slice(data.G,F.col(j),GFj);
                GF.col(j) = GFj;
            }
            mode<int>(GF,2,GG);
            data.G=GG;
        }
        //printf("group_sum_matrix()\n");
        group_sum_matrix(data.G,G_sum);
    }
    SparseMatrix<double> G_sum_dim;
    repdiag(G_sum,data.dim,G_sum_dim);
    assert(G_sum_dim.cols() == data.CSM.rows());
    data.CSM = (G_sum_dim * data.CSM).eval();


    arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K);
    if(flat)
    {
        data.K = (ref_map_dim * data.K).eval();
    }
    assert(data.K.rows() == data.n*data.dim);

    SparseMatrix<double> Q = (-L).eval();

    if(data.with_dynamics)
    {
        const double h = data.h;
        assert(h != 0);
        SparseMatrix<double> M;
        massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
        const double dw = (1./data.ym)*(h*h);
        SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
        Q += DQ;
        // Dummy external forces
        data.f_ext = MatrixXd::Zero(n,data.dim);
        data.vel = MatrixXd::Zero(n,data.dim);
    }

    return min_quad_with_fixed_precompute(
               Q,b,SparseMatrix<double>(),true,data.solver_data);
}
Esempio n. 10
0
IGL_INLINE void igl::adjacency_list(
    const Eigen::PlainObjectBase<Index>  & F,
    std::vector<std::vector<IndexVector> >& A,
    bool sorted)
{
  A.clear(); 
  A.resize(F.maxCoeff()+1);
  
  // Loop over faces
  for(int i = 0;i<F.rows();i++)
  {
    // Loop over this face
    for(int j = 0;j<F.cols();j++)
    {
      // Get indices of edge: s --> d
      int s = F(i,j);
      int d = F(i,(j+1)%F.cols());
      A.at(s).push_back(d);
      A.at(d).push_back(s);
    }
  }
  
  // Remove duplicates
  for(int i=0; i<(int)A.size();++i)
  {
    std::sort(A[i].begin(), A[i].end());
    A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
  }
  
  // If needed, sort every VV
  if (sorted)
  {
    // Loop over faces
    
    // for every vertex v store a set of ordered edges not incident to v that belongs to triangle incident on v.
    std::vector<std::vector<std::vector<int> > > SR; 
    SR.resize(A.size());
    
    for(int i = 0;i<F.rows();i++)
    {
      // Loop over this face
      for(int j = 0;j<F.cols();j++)
      {
        // Get indices of edge: s --> d
        int s = F(i,j);
        int d = F(i,(j+1)%F.cols());
        // Get index of opposing vertex v
        int v = F(i,(j+2)%F.cols());
        
        std::vector<int> e(2);
        e[0] = d;
        e[1] = v;
        SR[s].push_back(e);
      }
    }
    
    for(int v=0; v<(int)SR.size();++v)
    {
      std::vector<IndexVector>& vv = A.at(v);
      std::vector<std::vector<int> >& sr = SR[v];
      
      std::vector<std::vector<int> > pn = sr;
      
      // Compute previous/next for every element in sr
      for(int i=0;i<(int)sr.size();++i)
      {
        int a = sr[i][0];
        int b = sr[i][1];
        
        // search for previous
        int p = -1;
        for(int j=0;j<(int)sr.size();++j)
          if(sr[j][1] == a)
            p = j;
        pn[i][0] = p;
        
        // search for next
        int n = -1;
        for(int j=0;j<(int)sr.size();++j)
          if(sr[j][0] == b)
            n = j;
        pn[i][1] = n;
        
      }
      
      // assume manifoldness (look for beginning of a single chain)
      int c = 0;
      for(int j=0; j<=(int)sr.size();++j)
        if (pn[c][0] != -1)
          c = pn[c][0];
      
      if (pn[c][0] == -1) // border case
      {
        // finally produce the new vv relation
        for(int j=0; j<(int)sr.size();++j)
        {
          vv[j] = sr[c][0];
          if (pn[c][1] != -1)
            c = pn[c][1];
        }
        vv.back() = sr[c][1];
      }
      else
      {
        // finally produce the new vv relation
        for(int j=0; j<(int)sr.size();++j)
        {
          vv[j] = sr[c][0];
          
          c = pn[c][1];
        }
      }
    }
  }
}
Esempio n. 11
0
void igl::bfs_orient(
  const Eigen::PlainObjectBase<DerivedF> & F,
  Eigen::PlainObjectBase<DerivedFF> & FF,
  Eigen::PlainObjectBase<DerivedC> & C)
{
  using namespace Eigen;
  using namespace igl;
  using namespace std;
  SparseMatrix<int> A;
  manifold_patches(F,C,A);

  // number of faces
  const int m = F.rows();
  // number of patches
  const int num_cc = C.maxCoeff()+1;
  VectorXi seen = VectorXi::Zero(m);

  // Edge sets
  const int ES[3][2] = {{1,2},{2,0},{0,1}};

  if(&FF != &F)
  {
    FF = F;
  }
  // loop over patches
#pragma omp parallel for
  for(int c = 0;c<num_cc;c++)
  {
    queue<int> Q;
    // find first member of patch c
    for(int f = 0;f<FF.rows();f++)
    {
      if(C(f) == c)
      {
        Q.push(f);
        break;
      }
    }
    assert(!Q.empty());
    while(!Q.empty())
    {
      const int f = Q.front();
      Q.pop();
      if(seen(f) > 0)
      {
        continue;
      }
      seen(f)++;
      // loop over neighbors of f
      for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
      {
        // might be some lingering zeros, and skip self-adjacency
        if(it.value() != 0 && it.row() != f)
        {
          const int n = it.row();
          assert(n != f);
          // loop over edges of f
          for(int efi = 0;efi<3;efi++)
          {
            // efi'th edge of face f
            Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
            // loop over edges of n
            for(int eni = 0;eni<3;eni++)
            {
              // eni'th edge of face n
              Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
              // Match (half-edges go same direction)
              if(ef(0) == en(0) && ef(1) == en(1))
              {
                // flip face n
                FF.row(n) = FF.row(n).reverse().eval();
              }
            }
          }
          // add neighbor to queue
          Q.push(n);
        }
      }
    }
  }

  // make sure flip is OK if &FF = &F
}
IGL_INLINE void igl::reorient_facets_raycast(
  const Eigen::PlainObjectBase<DerivedV> & V,
  const Eigen::PlainObjectBase<DerivedF> & F,
  int rays_total,
  int rays_minimum,
  bool facet_wise,
  bool use_parity,
  bool is_verbose,
  Eigen::PlainObjectBase<DerivedI> & I,
  Eigen::PlainObjectBase<DerivedC> & C)
{
  using namespace Eigen;
  using namespace std;
  assert(F.cols() == 3);
  assert(V.cols() == 3);
  
  // number of faces
  const int m = F.rows();
  
  MatrixXi FF = F;
  if (facet_wise) {
    C.resize(m);
    for (int i = 0; i < m; ++i) C(i) = i;
  
  } else {
    if (is_verbose) cout << "extracting patches... ";
    bfs_orient(F,FF,C);
  }
  if (is_verbose) cout << (C.maxCoeff() + 1)  << " components. ";
  
  // number of patches
  const int num_cc = C.maxCoeff()+1;
  
  // Init Embree
  EmbreeIntersector ei;
  ei.init(V.template cast<float>(),FF);
  
  // face normal
  MatrixXd N;
  per_face_normals(V,FF,N);
  
  // face area
  Matrix<typename DerivedV::Scalar,Dynamic,1> A;
  doublearea(V,FF,A);
  double area_total = A.sum();
  
  // determine number of rays per component according to its area
  VectorXd area_per_component;
  area_per_component.setZero(num_cc);
  for (int f = 0; f < m; ++f)
  {
    area_per_component(C(f)) += A(f);
  }
  VectorXi num_rays_per_component(num_cc);
  for (int c = 0; c < num_cc; ++c)
  {
    num_rays_per_component(c) = max<int>(static_cast<int>(rays_total * area_per_component(c) / area_total), rays_minimum);
  }
  rays_total = num_rays_per_component.sum();
  
  // generate all the rays
  if (is_verbose) cout << "generating rays... ";
  uniform_real_distribution<float> rdist;
  mt19937 prng;
  prng.seed(time(nullptr));
  vector<int     > ray_face;
  vector<Vector3f> ray_ori;
  vector<Vector3f> ray_dir;
  ray_face.reserve(rays_total);
  ray_ori .reserve(rays_total);
  ray_dir .reserve(rays_total);
  for (int c = 0; c < num_cc; ++c)
  {
    if (area_per_component[c] == 0)
    {
      continue;
    }
    vector<int> CF;     // set of faces per component
    vector<double> CF_area;
    for (int f = 0; f < m; ++f)
    {
      if (C(f)==c)
      {
        CF.push_back(f);
        CF_area.push_back(A(f));
      }
    }
    // discrete distribution for random selection of faces with probability proportional to their areas
    discrete_distribution<int> ddist(CF.size(), 0, CF.size(), [&](double i){ return CF_area[static_cast<int>(i)]; });       // simple ctor of (Iter, Iter) not provided by the stupid VC11/12
    for (int i = 0; i < num_rays_per_component[c]; ++i)
    {
      int f = CF[ddist(prng)];          // select face with probability proportional to face area
      float s = rdist(prng);            // random barycentric coordinate (reference: Generating Random Points in Triangles [Turk, Graphics Gems I 1990])
      float t = rdist(prng);
      float sqrt_t = sqrtf(t);
      float a = 1 - sqrt_t;
      float b = (1 - s) * sqrt_t;
      float c = s * sqrt_t;
      Vector3f p = a * V.row(FF(f,0)).template cast<float>().eval()       // be careful with the index!!!
                 + b * V.row(FF(f,1)).template cast<float>().eval()
                 + c * V.row(FF(f,2)).template cast<float>().eval();
      Vector3f n = N.row(f).cast<float>();
      if (n.isZero()) continue;
      // random direction in hemisphere around n (avoid too grazing angle)
      Vector3f d;
      while (true) {
        d = random_dir().cast<float>();
        float ndotd = n.dot(d);
        if (fabsf(ndotd) < 0.1f)
        {
          continue;
        }
        if (ndotd < 0)
        {
          d *= -1.0f;
        }
        break;
      }
      ray_face.push_back(f);
      ray_ori .push_back(p);
      ray_dir .push_back(d);

      if (is_verbose && ray_face.size() % (rays_total / 10) == 0) cout << ".";
    }
  }
  if (is_verbose) cout << ray_face.size()  << " rays. ";
  
  // per component voting: first=front, second=back
  vector<pair<float, float>> C_vote_distance(num_cc, make_pair(0, 0));      // sum of distance between ray origin and intersection
  vector<pair<int  , int  >> C_vote_infinity(num_cc, make_pair(0, 0));      // number of rays reaching infinity
  vector<pair<int  , int  >> C_vote_parity(num_cc, make_pair(0, 0));        // sum of parity count for each ray
  
  if (is_verbose) cout << "shooting rays... ";
#pragma omp parallel for
  for (int i = 0; i < (int)ray_face.size(); ++i)
  {
    int      f = ray_face[i];
    Vector3f o = ray_ori [i];
    Vector3f d = ray_dir [i];
    int c = C(f);
    
    // shoot ray toward front & back
    vector<Hit> hits_front;
    vector<Hit> hits_back;
    int num_rays_front;
    int num_rays_back;
    ei.intersectRay(o,  d, hits_front, num_rays_front);
    ei.intersectRay(o, -d, hits_back , num_rays_back );
    if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin());
    if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin());
    
    if (use_parity) {
#pragma omp atomic
      C_vote_parity[c].first  += hits_front.size() % 2;
#pragma omp atomic
      C_vote_parity[c].second += hits_back .size() % 2;
    
    } else {
      if (hits_front.empty())
      {
#pragma omp atomic
        C_vote_infinity[c].first++;
      } else {
#pragma omp atomic
        C_vote_distance[c].first += hits_front[0].t;
      }
    
      if (hits_back.empty())
      {
#pragma omp atomic
        C_vote_infinity[c].second++;
      } else {
#pragma omp atomic
        C_vote_distance[c].second += hits_back[0].t;
      }
    }
  }
  
  I.resize(m);
  for(int f = 0; f < m; ++f)
  {
    int c = C(f);
    if (use_parity) {
      I(f) = C_vote_parity[c].first > C_vote_parity[c].second ? 1 : 0;      // Ideally, parity for the front/back side should be 1/0 (i.e., parity sum for all rays should be smaller on the front side)
    
    } else {
      I(f) = (C_vote_infinity[c].first == C_vote_infinity[c].second && C_vote_distance[c].first <  C_vote_distance[c].second) ||
              C_vote_infinity[c].first <  C_vote_infinity[c].second
              ? 1 : 0;
    }
    // To account for the effect of bfs_orient
    if (F.row(f) != FF.row(f))
      I(f) = 1 - I(f);
  }
  if (is_verbose) cout << "done!" << endl;
}
Esempio n. 13
0
IGL_INLINE void igl::boundary_loop(
    const Eigen::PlainObjectBase<DerivedF> & F, 
    std::vector<std::vector<Index> >& L)
{
  using namespace std;
  using namespace Eigen;
  using namespace igl;

  MatrixXd Vdummy(F.maxCoeff(),1);
  MatrixXi TT,TTi;
  vector<std::vector<int> > VF, VFi;
  triangle_triangle_adjacency(Vdummy,F,TT,TTi);
  vertex_triangle_adjacency(Vdummy,F,VF,VFi);

  vector<bool> unvisited = is_border_vertex(Vdummy,F);
  set<int> unseen;
  for (int i = 0; i < unvisited.size(); ++i)
  {
    if (unvisited[i])
      unseen.insert(unseen.end(),i);
  }

  while (!unseen.empty())
  {
    vector<Index> l;

    // Get first vertex of loop
    int start = *unseen.begin();
    unseen.erase(unseen.begin());
    unvisited[start] = false;
    l.push_back(start);

    bool done = false;
    while (!done)
    {
      // Find next vertex
      bool newBndEdge = false;
      int v = l[l.size()-1];
      int next;
      for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++)
      {
        int fid = VF[v][i];

        if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge
        {
          int vLoc;
          if (F(fid,0) == v) vLoc = 0;
          if (F(fid,1) == v) vLoc = 1;
          if (F(fid,2) == v) vLoc = 2;

          int vPrev = F(fid,(vLoc + F.cols()-1) % F.cols());
          int vNext = F(fid,(vLoc + 1) % F.cols());

          bool newBndEdge = false;
          if (unvisited[vPrev] && TT(fid,(vLoc+2) % F.cols()) < 0)
          {
            next = vPrev;
            newBndEdge = true;
          }
          else if (unvisited[vNext] && TT(fid,vLoc) < 0)
          {
            next = vNext;
            newBndEdge = true;
          }
        }
      }

      if (newBndEdge)
      {
        l.push_back(next);
        unseen.erase(next);
        unvisited[next] = false;
      }
      else
        done = true;
    }
    L.push_back(l);
  }
}
Esempio n. 14
0
IGL_INLINE void igl::orient_outward(
  const Eigen::PlainObjectBase<DerivedV> & V,
  const Eigen::PlainObjectBase<DerivedF> & F,
  const Eigen::PlainObjectBase<DerivedC> & C,
  Eigen::PlainObjectBase<DerivedFF> & FF,
  Eigen::PlainObjectBase<DerivedI> & I)
{
  using namespace Eigen;
  using namespace std;
  assert(C.rows() == F.rows());
  assert(F.cols() == 3);
  assert(V.cols() == 3);

  // number of faces
  const int m = F.rows();
  // number of patches
  const int num_cc = C.maxCoeff()+1;
  I.resize(num_cc);
  if(&FF != &F)
  {
    FF = F;
  }
  PlainObjectBase<DerivedV> N,BC,BCmean;
  Matrix<typename DerivedV::Scalar,Dynamic,1> A;
  VectorXd totA(num_cc), dot(num_cc);
  Matrix<typename DerivedV::Scalar,3,1> Z(1,1,1);
  per_face_normals(V,F,Z.normalized(),N);
  barycenter(V,F,BC);
  doublearea(V,F,A);
  BCmean.setConstant(num_cc,3,0);
  dot.setConstant(num_cc,1,0);
  totA.setConstant(num_cc,1,0);
  // loop over faces
  for(int f = 0;f<m;f++)
  {
    BCmean.row(C(f)) += A(f)*BC.row(f);
    totA(C(f))+=A(f);
  }
  // take area weighted average
  for(int c = 0;c<num_cc;c++)
  {
    BCmean.row(c) /= (typename DerivedV::Scalar) totA(c);
  }
  // subtract bcmean
  for(int f = 0;f<m;f++)
  {
    BC.row(f) -= BCmean.row(C(f));
    dot(C(f)) += A(f)*N.row(f).dot(BC.row(f));
  }
  // take area weighted average
  for(int c = 0;c<num_cc;c++)
  {
    dot(c) /= (typename DerivedV::Scalar) totA(c);
    if(dot(c) < 0)
    {
      I(c) = true;
    }else
    {
      I(c) = false;
    }
  }
  // flip according to I
  for(int f = 0;f<m;f++)
  {
    if(I(C(f)))
    {
      FF.row(f) = FF.row(f).reverse().eval();
    }
  }
}