// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2025 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 "variable_radius_offset.h" #include "SphereMeshWedge.h" #include "marching_cubes.h" #include "unique_sparse_voxel_corners.h" #include "lipschitz_octree.h" #include "eytzinger_aabb.h" #include "eytzinger_aabb_sdf.h" #include "get_seconds.h" #include "parallel_for.h" #include template < typename DerivedV, typename DerivedF, typename DerivedR, typename Derivedorigin, typename DerivedmV, typename DerivedmF> void igl::variable_radius_offset( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, const Eigen::MatrixBase & R, const Eigen::MatrixBase & origin, const typename Derivedorigin::Scalar h0, const int max_depth, Eigen::PlainObjectBase & mV, Eigen::PlainObjectBase & mF) { using Scalar = typename DerivedV::Scalar; Eigen::Matrix PB1,PB2; std::vector> data; std::function &,const int i)> primitive; igl::variable_radius_offset(V,F,R,PB1,PB2,data,primitive); igl::variable_radius_offset( PB1,PB2,data,primitive,origin,h0,max_depth,mV,mF); } template < typename DerivedV, typename DerivedF, typename DerivedR, typename DerivedPB1, typename DerivedPB2, typename Scalar> void igl::variable_radius_offset( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, const Eigen::MatrixBase & R, Eigen::PlainObjectBase & PB1, Eigen::PlainObjectBase & PB2, std::vector> & data, std::function &,const int i)> & primitive) { // Bounds PB1.setConstant(F.rows(),3,std::numeric_limits::infinity()); PB2.setConstant(F.rows(),3,-std::numeric_limits::infinity()); for(int f = 0;f( V.row(F(f,0)),V.row(F(f,1)),V.row(F(f,2)), R(F(f,0)),R(F(f,1)),R(F(f,2))); } // I suppose primitive could just capture `data` by value. Then it owns the // data and we don't need to worry about `data` getting destroyed before its // called. I'm not sure how expensive that copy would be. primitive = [&](const Eigen::RowVector3d & p, const int i) { return data[i](p); }; } template < typename DerivedPB1, typename DerivedPB2, typename Scalar, typename Derivedorigin, typename DerivedmV, typename DerivedmF> void igl::variable_radius_offset( const Eigen::MatrixBase & PB1, const Eigen::MatrixBase & PB2, const std::vector> & data, const std::function &,const int i)> & primitive, const Eigen::MatrixBase & origin, const Scalar h0, const int max_depth, Eigen::PlainObjectBase & mV, Eigen::PlainObjectBase & mF) { using RowVector3S = Eigen::Matrix; IGL_TICTOC_LAMBDA; tictoc(); Eigen::Matrix B1,B2; Eigen::VectorXi leaf; igl::eytzinger_aabb(PB1,PB2,B1,B2,leaf); printf("%-20s: %g secs\n","eytzinger_aabb",tictoc()); const std::function sdf = [&](const RowVector3S & p) -> Scalar { const std::function primitive_p = [&](const int j) { return primitive(p,j); }; Scalar f; igl::eytzinger_aabb_sdf(p,primitive_p,B1,B2,leaf,f); return f; }; const std::function udf = [&](const RowVector3S & p) -> Scalar { return std::abs(sdf(p)); //// This made performance worse. //const std::function primitive_p = [&](const int j) //{ // const Scalar d = udTriangle( V.row(F(j,0)), V.row(F(j,1)), V.row(F(j,2)), p); // const RowVector3S r(R(F(j,0)),R(F(j,1)),R(F(j,2))); // const Scalar min_r = r.minCoeff(); // const Scalar max_r = r.maxCoeff(); // if(d > max_r) // { // return d - max_r; // }else if(d < min_r) // { // return d - min_r; // } // return 0.0; //}; //Scalar f; //igl::eytzinger_aabb_sdf(p,primitive_p,B1,B2,leaf,f); //return f; }; Eigen::Matrix ijk; igl::lipschitz_octree( origin,h0,max_depth,udf,ijk); printf("%-20s: %g secs\n","lipschitz_octree",tictoc()); { tictoc(); // Gather the corners of those leaf cells const Scalar h = h0 / (1 << max_depth); Eigen::Matrix J; Eigen::Matrix unique_ijk; Eigen::Matrix unique_corner_positions; igl::unique_sparse_voxel_corners(origin,h0,max_depth,ijk,unique_ijk,J,unique_corner_positions); //printf("unique_sparse_voxel_corners: %0.7f seconds\n",tictoc()); printf("%-20s: %g secs\n","unique_sparse_vo...",tictoc()); /// Evaluate the signed distance function at the corners Eigen::VectorXd S(unique_corner_positions.rows()); //for(int u = 0;u, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase> const&, Eigen::MatrixBase> const&, Eigen::MatrixBase> const&, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&, std::vector, std::allocator>>&, std::function const&, int)>&); template void igl::variable_radius_offset, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const&, Eigen::MatrixBase> const&, Eigen::MatrixBase> const&, Eigen::MatrixBase> const&, Eigen::Matrix::Scalar, int, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&); #endif