简体   繁体   中英

How to perform Boolean operation on thin surface using libigl?

I am currently working on libigl , and trying to grab the part of the a surface which locates inside another body. However, it seems than libigl only works with closed bodies:

Here is the code which works for closed bodies. VA , VF is a triangular prism and VB , FB is a tetrahedron:

#include <igl/readOFF.h>
//#define IGL_NO_CORK
//#undef IGL_STATIC_LIBRARY
#include <igl/copyleft/cgal/mesh_boolean.h>
#include <igl/viewer/Viewer.h>

#include <Eigen/Core>
#include <iostream>

Eigen::MatrixXd VA,VB,VC;
Eigen::VectorXi J,I;
Eigen::MatrixXi FA,FB,FC;
igl::MeshBooleanType boolean_type(
  igl::MESH_BOOLEAN_TYPE_UNION);

const char * MESH_BOOLEAN_TYPE_NAMES[] =
{
  "Union",
  "Intersect",
  "Minus",
  "XOR",
  "Resolve",
};

bool key_down(igl::viewer::Viewer &viewer, unsigned char key, int mods)
{
  switch(key)
  {
    default:
      return false;
    case 'A':
        viewer.data.clear();
        std::cout << "Loading A" << std::endl;
        viewer.data.set_mesh(VA, FA);
      break;
    case 'B':
        viewer.data.clear();
        std::cout << "Loading B" << std::endl;
        viewer.data.set_mesh(VB, FB);
      break;
    case 'C':
        viewer.data.clear();
        std::cout << "Loading C" << std::endl;
        viewer.data.set_mesh(VC, FC);
      return true;
  }  
  return true;
}

int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;

  double prismSize = 150;
  double Heigh = 300;
  VA.resize(6, 3);
  VA << -prismSize, prismSize, 0,
      prismSize, prismSize, 0,
      0, 2 * prismSize, 0,
      -prismSize, prismSize, Heigh,
      prismSize, prismSize, Heigh,
      0, 2 * prismSize, Heigh;
  FA.resize(8, 3);
  FA << 1, 0, 2,
      5, 3, 4,
      4, 1, 2,
      2, 5, 4,
      3, 5, 2,
      2, 0, 3,
      0, 1, 4,
      4, 3, 0;

  double tetsize = 300;
  VB.resize(4, 3);
  VB << 0, 0, tetsize,
      -tetsize, 0, 0,
      tetsize, 0, 0,
      0, tetsize*2, 0;
  FB.resize(4, 3);
  FB << 2, 1, 3,
      2, 0, 1,
      3, 0, 2,
      1, 0, 3;


  igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, igl::MESH_BOOLEAN_TYPE_INTERSECT, VC, FC);

  std::cout
      << "VA:" << std::endl << VA << std::endl << "==============" << std::endl
      << "FA:" << std::endl << FA << std::endl << "==============" << std::endl
      << "VB:" << std::endl << VB << std::endl << "==============" << std::endl
      << "FB:" << std::endl << FB << std::endl << "==============" << std::endl
      << "VC:" << std::endl << VC << std::endl << "==============" << std::endl
      << "FC:" << std::endl << FC << std::endl << "==============" << std::endl;

  // Plot the mesh with pseudocolors
  igl::viewer::Viewer viewer;

  viewer.data.set_mesh(VA, FA);
  //viewer.data.set_mesh(VB, FB);
  //viewer.data.set_mesh(VC, FC);  

  viewer.core.show_lines = true;
  viewer.callback_key_down = &key_down;
  viewer.core.camera_dnear = 3.9;
  cout<<
    "Press '.' to switch to next boolean operation type."<<endl<<
    "Press ',' to switch to previous boolean operation type."<<endl<<
    "Press ']' to push near cutting plane away from camera."<<endl<<
    "Press '[' to pull near cutting plane closer to camera."<<endl<<
    "Hint: investigate _inside_ the model to see orientation changes."<<endl;
  viewer.launch();
}

However, if I deleted one of the surfaces from A or B , like below for example:

//FA.resize(8, 3);
FA.resize(7, 3);
//FA << 1, 0, 2,
FA << 5, 3, 4,
      4, 1, 2,
      2, 5, 4,
      3, 5, 2,
      2, 0, 3,
      0, 1, 4,
      4, 3, 0;

The result mesh C will be empty (I want to get a open thin surface instead of a closed body). I think I am using the wrong function. Anyone knows how to do this?

Boolean geometry requires that all surfaces are manifold without boundary. Any operations will result in an empty set otherwise. Here is a simple explination of manifolds:

Manifolds

...and more reasoning on your question:

Boolean Operations

You might be looking for igl::copyleft::cgal::trim_with_solid . This assumes you have an arbitrary mesh A and you have another closed mesh (actually a solid or PWN mesh) B . The output will be a mesh of the same surface as A but with new edges added so that every face can be either flagged as inside B or outside/on B . Using the flags in the output list D , it's then trivial to extract the portion of A "trimmed" by B .

igl::copyleft::cgal::trim_with_solid(VA,FA,VB,FB,V,F,D,J);

As described by @Eric Bischoff , Boolean geometry requires that all surfaces are manifold. However, I found a workaround for this, which at least fits with my requirement:

Assume that A is an arbitrary open surface and B is a closed manifold, and you want to cut off the outside part of surface A .

The workaround I want to describes, is to complete A to make it a manifold ( A' ) firstly. Then, subtract A' from B, and find the newly created facets, which exactly constitute the open thin surface you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM