1

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?

Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88
Wesley Ranger
  • 770
  • 1
  • 7
  • 26

3 Answers3

3

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);
Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88
  • So, what is `J` used for? It seems `J` frequently appears in APIs related to boolean, but I didn't find clear information about it. – Wesley Ranger Apr 27 '17 at 05:59
  • `J` is going to tell you which face of the _input_ each face of the _output_ comes from. So suppose each face of your input had a different color, then `J` would tell you how to color your output mesh to match correctly. – Alec Jacobson May 10 '17 at 22:42
1

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

Community
  • 1
  • 1
1

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.

Wesley Ranger
  • 770
  • 1
  • 7
  • 26
  • 1
    Although I'm unaware of your data set and use case: You could close up every contiguous boundary. If you have access to the halve edge data structure I believe you could just find ever neighboring edge that has exactly one neighboring face. This wouldn't work for all cases, but depending on your data it could work for most. –  Jun 23 '16 at 14:12
  • That's about as far as I'm able to take it as I've never used libigl. Good luck:) –  Jun 23 '16 at 14:14
  • @user5454506 Yes, my data structure is special, so I can use this route. Recently I am faced with a new geometry which can't be closed easily. I am gonna try `igl::copyleft::cgal::trim_with_solid(VA,FA,VB,FB,V,F,D,J);` suggested by @Alec Jacobson – Wesley Ranger Apr 27 '17 at 05:33