// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2016 Alec Jacobson // // 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 "minkowski_sum.h" #include "mesh_boolean.h" #include "../../slice.h" #include "../../slice_mask.h" #include "../../LinSpaced.h" #include "../../unique_rows.h" #include "../../get_seconds.h" #include "../../edges.h" #include #include #include #include template < typename DerivedVA, typename DerivedFA, typename DerivedVB, typename DerivedFB, typename DerivedW, typename DerivedG, typename DerivedJ> IGL_INLINE void igl::copyleft::cgal::minkowski_sum( const Eigen::MatrixBase & VA, const Eigen::MatrixBase & FA, const Eigen::MatrixBase & VB, const Eigen::MatrixBase & FB, const bool resolve_overlaps, Eigen::PlainObjectBase & W, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J) { using namespace std; using namespace Eigen; assert(FA.cols() == 3 && "FA must contain a closed triangle mesh"); assert(FB.cols() <= FA.cols() && "FB must contain lower diemnsional simplices than FA"); const auto tictoc = []()->double { static double t_start; double now = igl::get_seconds(); double interval = now-t_start; t_start = now; return interval; }; tictoc(); Matrix EB; edges(FB,EB); Matrix EA(0,2); if(FB.cols() == 3) { edges(FA,EA); } // number of copies of A along edges of B const int n_ab = EB.rows(); // number of copies of B along edges of A const int n_ba = EA.rows(); vector vW(n_ab + n_ba); vector vG(n_ab + n_ba); vector vJ(n_ab + n_ba); vector offsets(n_ab + n_ba + 1); offsets[0] = 0; // sweep A along edges of B for(int e = 0;e eJ; minkowski_sum( VA, FA, VB.row(EB(e,0)).eval(), VB.row(EB(e,1)).eval(), false, vW[e], vG[e], eJ); assert(vG[e].rows() == eJ.rows()); assert(eJ.cols() == 1); vJ[e].resize(vG[e].rows(),2); vJ[e].col(0) = eJ; vJ[e].col(1).setConstant(e); offsets[e+1] = offsets[e] + vW[e].rows(); } // sweep B along edges of A for(int e = 0;e eJ; const int ee = n_ab+e; minkowski_sum( VB, FB, VA.row(EA(e,0)).eval(), VA.row(EA(e,1)).eval(), false, vW[ee], vG[ee], eJ); vJ[ee].resize(vG[ee].rows(),2); vJ[ee].col(0) = eJ.array() + (FA.rows()+1); vJ[ee].col(1).setConstant(ee); offsets[ee+1] = offsets[ee] + vW[ee].rows(); } // Combine meshes int n=0,m=0; for_each(vW.begin(),vW.end(),[&n](const DerivedW & w){n+=w.rows();}); for_each(vG.begin(),vG.end(),[&m](const DerivedG & g){m+=g.rows();}); assert(n == offsets.back()); W.resize(n,3); G.resize(m,3); J.resize(m,2); { int m_off = 0,n_off = 0; for(int i = 0;i SJ; mesh_boolean( DerivedW(W), DerivedG(G), Matrix(), Matrix(), MESH_BOOLEAN_TYPE_UNION, W, G, SJ); slice(DerivedJ(J),SJ,1,J); } } template < typename DerivedVA, typename DerivedFA, typename sType, int sCols, int sOptions, typename dType, int dCols, int dOptions, typename DerivedW, typename DerivedG, typename DerivedJ> IGL_INLINE void igl::copyleft::cgal::minkowski_sum( const Eigen::MatrixBase & VA, const Eigen::MatrixBase & FA, const Eigen::Matrix & s, const Eigen::Matrix & d, const bool resolve_overlaps, Eigen::PlainObjectBase & W, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J) { using namespace Eigen; using namespace std; assert(s.cols() == 3 && "s should be a 3d point"); assert(d.cols() == 3 && "d should be a 3d point"); // silly base case if(FA.size() == 0) { W.resize(0,3); G.resize(0,3); return; } const int dim = VA.cols(); assert(dim == 3 && "dim must be 3D"); assert(s.size() == 3 && "s must be 3D point"); assert(d.size() == 3 && "d must be 3D point"); // segment vector const CGAL::Vector_3 v(d(0)-s(0),d(1)-s(1),d(2)-s(2)); // number of vertices const int n = VA.rows(); // duplicate vertices at s and d, we'll remove unreferernced later W.resize(2*n,dim); for(int i = 0;i P(m,1),N(m,1); // loop over faces int mp = 0,mn = 0; for(int f = 0;f plane( CGAL::Point_3(VA(FA(f,0),0),VA(FA(f,0),1),VA(FA(f,0),2)), CGAL::Point_3(VA(FA(f,1),0),VA(FA(f,1),1),VA(FA(f,1),2)), CGAL::Point_3(VA(FA(f,2),0),VA(FA(f,2),1),VA(FA(f,2),2))); const auto normal = plane.orthogonal_vector(); const auto dt = normal * v; if(dt > 0) { P(f) = true; N(f) = false; mp++; }else //}else if(dt < 0) { P(f) = false; N(f) = true; mn++; //}else //{ // P(f) = false; // N(f) = false; } } typedef Matrix MatrixXI; typedef Matrix VectorXI; MatrixXI GT(mp+mn,3); GT<< slice_mask(FA,N,1), slice_mask((FA.array()+n).eval(),P,1); // J indexes FA for parts at s and m+FA for parts at d J.derived() = igl::LinSpaced(m,0,m-1); DerivedJ JT(mp+mn); JT << slice_mask(J,P,1), slice_mask(J,N,1); JT.block(mp,0,mn,1).array()+=m; // Original non-co-planar faces with positively oriented reversed MatrixXI BA(mp+mn,3); BA << slice_mask(FA,P,1).rowwise().reverse(), slice_mask(FA,N,1); // Quads along **all** sides MatrixXI GQ((mp+mn)*3,4); GQ<< BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n, BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n, BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n; MatrixXI uGQ; VectorXI S,sI,sJ; // Inputs: // F #F by d list of polygons // Outputs: // S #uF list of signed incidences for each unique face // uF #uF by d list of unique faces // I #uF index vector so that uF = sort(F,2)(I,:) // J #F index vector so that sort(F,2) = uF(J,:) []( const MatrixXI & F, VectorXI & S, MatrixXI & uF, VectorXI & I, VectorXI & J) { const int m = F.rows(); const int d = F.cols(); MatrixXI sF = F; const auto MN = sF.rowwise().minCoeff().eval(); // rotate until smallest index is first for(int p = 0;p M = Matrix::Zero(m,1); { VectorXI P = igl::LinSpaced(d,0,d-1); for(int p = 0;p SJ; mesh_boolean( DerivedW(W),DerivedG(G), Matrix(),MatrixXI(), MESH_BOOLEAN_TYPE_UNION, W,G,SJ); J.derived() = slice(DerivedJ(J),SJ,1); } } template < typename DerivedVA, typename DerivedFA, typename sType, int sCols, int sOptions, typename dType, int dCols, int dOptions, typename DerivedW, typename DerivedG, typename DerivedJ> IGL_INLINE void igl::copyleft::cgal::minkowski_sum( const Eigen::MatrixBase & VA, const Eigen::MatrixBase & FA, const Eigen::Matrix & s, const Eigen::Matrix & d, Eigen::PlainObjectBase & W, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J) { return minkowski_sum(VA,FA,s,d,true,W,G,J); } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template void igl::copyleft::cgal::minkowski_sum, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Lazy_exact_nt, 3, 1, CGAL::Lazy_exact_nt, 3, 1, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::Matrix, 1, 3, 1, 1, 3> const&, Eigen::Matrix, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); // generated by autoexplicit.sh template void igl::copyleft::cgal::minkowski_sum< Eigen::Matrix, Eigen::Matrix, double, 3, 1, float, 3, 1, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif