Determining if a point is inside a polyhedron

前端 未结 3 1462
粉色の甜心
粉色の甜心 2021-02-10 02:03

I\'m attempting to determine if a specific point lies inside a polyhedron. In my current implementation, the method I\'m working on take the point we\'re looking for an array of

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-02-10 02:15

    The link in your question has expired and I could not understand the algorithm from your code. Assuming you have a convex polyhedron with counterclockwise oriented faces (seen from outside), it should be sufficient to check that your point is behind all faces. To do that, you can take the vector from the point to each face and check the sign of the scalar product with the face's normal. If it is positive, the point is behind the face; if it is zero, the point is on the face; if it is negative, the point is in front of the face.

    Here is some complete C++11 code, that works with 3-point faces or plain more-point faces (only the first 3 points are considered). You can easily change bound to exclude the boundaries.

    #include 
    #include 
    #include 
    #include 
    
    struct Vector {
      double x, y, z;
    
      Vector operator-(Vector p) const {
        return Vector{x - p.x, y - p.y, z - p.z};
      }
    
      Vector cross(Vector p) const {
        return Vector{
          y * p.z - p.y * z,
          z * p.x - p.z * x,
          x * p.y - p.x * y
        };
      }
    
      double dot(Vector p) const {
        return x * p.x + y * p.y + z * p.z;
      }
    
      double norm() const {
        return std::sqrt(x*x + y*y + z*z);
      }
    };
    
    using Point = Vector;
    
    struct Face {
      std::vector v;
    
      Vector normal() const {
        assert(v.size() > 2);
        Vector dir1 = v[1] - v[0];
        Vector dir2 = v[2] - v[0];
        Vector n  = dir1.cross(dir2);
        double d = n.norm();
        return Vector{n.x / d, n.y / d, n.z / d};
      }
    };
    
    bool isInConvexPoly(Point const& p, std::vector const& fs) {
      for (Face const& f : fs) {
        Vector p2f = f.v[0] - p;         // f.v[0] is an arbitrary point on f
        double d = p2f.dot(f.normal());
        d /= p2f.norm();                 // for numeric stability
    
        constexpr double bound = -1e-15; // use 1e15 to exclude boundaries
        if (d < bound)
          return false;
      }
    
      return true;
    }
    
    int main(int argc, char* argv[]) {
      assert(argc == 3+1);
      char* end;
      Point p;
      p.x = std::strtod(argv[1], &end);
      p.y = std::strtod(argv[2], &end);
      p.z = std::strtod(argv[3], &end);
    
      std::vector cube{ // faces with 4 points, last point is ignored
        Face{{Point{0,0,0}, Point{1,0,0}, Point{1,0,1}, Point{0,0,1}}}, // front
        Face{{Point{0,1,0}, Point{0,1,1}, Point{1,1,1}, Point{1,1,0}}}, // back
        Face{{Point{0,0,0}, Point{0,0,1}, Point{0,1,1}, Point{0,1,0}}}, // left
        Face{{Point{1,0,0}, Point{1,1,0}, Point{1,1,1}, Point{1,0,1}}}, // right
        Face{{Point{0,0,1}, Point{1,0,1}, Point{1,1,1}, Point{0,1,1}}}, // top
        Face{{Point{0,0,0}, Point{0,1,0}, Point{1,1,0}, Point{1,0,0}}}, // bottom
      };
    
      std::cout << (isInConvexPoly(p, cube) ? "inside" : "outside") << std::endl;
    
      return 0;
    }
    

    Compile it with your favorite compiler

    clang++ -Wall -std=c++11 code.cpp -o inpoly
    

    and test it like

    $ ./inpoly 0.5 0.5 0.5
    inside
    $ ./inpoly 1 1 1
    inside
    $ ./inpoly 2 2 2
    outside
    

提交回复
热议问题