IGL_INLINE bool igl::copyleft::cgal::triangle_triangle_squared_distance(
  const CGAL::Triangle_3<Kernel> & T1,
  const CGAL::Triangle_3<Kernel> & T2,
  CGAL::Point_3<Kernel> & P1,
  CGAL::Point_3<Kernel> & P2,
  typename Kernel::FT & d)
{
  typedef CGAL::Point_3<Kernel> Point_3;
  typedef CGAL::Vector_3<Kernel> Vector_3;
  typedef CGAL::Triangle_3<Kernel> Triangle_3;
  typedef CGAL::Segment_3<Kernel> Segment_3;
  typedef typename Kernel::FT EScalar;
  assert(!T1.is_degenerate());
  assert(!T2.is_degenerate());

  bool unique = true;
  if(CGAL::do_intersect(T1,T2))
  {
    // intersecting triangles have zero (squared) distance
    CGAL::Object result = CGAL::intersection(T1,T2);
    // Some point on the intersection result
    CGAL::Point_3<Kernel> Q;
    if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
    {
      Q = *p;
    }else if(const Segment_3 * s = CGAL::object_cast<Segment_3 >(&result))
    {
      unique = false;
      Q = s->source();
    }else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&result))
    {
      Q = s->vertex(0);
      unique = false;
    }else if(const std::vector<Point_3 > *polyp = 
      CGAL::object_cast< std::vector<Point_3 > >(&result))
    {
      assert(polyp->size() > 0 && "intersection poly should not be empty");
      Q = polyp[0];
      unique = false;
    }else
    {
      assert(false && "Unknown intersection result");
    }
    P1 = Q;
    P2 = Q;
    d = 0;
    return unique;
  }
  // triangles do not intersect: the points of closest approach must be on the
  // boundary of one of the triangles
  d = std::numeric_limits<double>::infinity();
  const auto & vertices_face = [&unique](
    const Triangle_3 & T1,
    const Triangle_3 & T2,
    Point_3 & P1,
    Point_3 & P2,
    EScalar & d)
  {
    for(int i = 0;i<3;i++)
    {
      const Point_3 vi = T1.vertex(i);
      Point_3 P2i;
      EScalar di;
      point_triangle_squared_distance(vi,T2,P2i,di);
      if(di<d)
      {
        d = di;
        P1 = vi;
        P2 = P2i;
        unique = true;
      }else if(d == di)
      {
        // edge of T1 floating parallel above T2
        unique = false;
      }
    }
  };
  vertices_face(T1,T2,P1,P2,d);
  vertices_face(T2,T1,P1,P2,d);
  for(int i = 0;i<3;i++)
  {
    const Segment_3 s1( T1.vertex(i+1), T1.vertex(i+2));
    for(int j = 0;j<3;j++)
    {
      const Segment_3 s2( T2.vertex(i+1), T2.vertex(i+2));
      Point_3 P1ij;
      Point_3 P2ij;
      EScalar dij;
      bool uniqueij = segment_segment_squared_distance(s1,s2,P1ij,P2ij,dij);
      if(dij < d)
      {
        P1 = P1ij;
        P2 = P2ij;
        d = dij;
        unique = uniqueij;
      }
    }
  }
  return unique;
}
IGL_INLINE void igl::cgal::projected_delaunay(
  const CGAL::Triangle_3<Kernel> & A,
  const std::vector<CGAL::Object> & A_objects_3,
  CGAL::Constrained_triangulation_plus_2<
    CGAL::Constrained_Delaunay_triangulation_2<
      Kernel,
      CGAL::Triangulation_data_structure_2<
        CGAL::Triangulation_vertex_base_2<Kernel>,
        CGAL::Constrained_triangulation_face_base_2<Kernel> >,
      CGAL::Exact_intersections_tag> > & cdt)
{
  using namespace std;
  // 3D Primitives
  typedef CGAL::Point_3<Kernel>    Point_3;
  typedef CGAL::Segment_3<Kernel>  Segment_3; 
  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
  typedef CGAL::Plane_3<Kernel>    Plane_3;
  //typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
  typedef CGAL::Point_2<Kernel>    Point_2;
  //typedef CGAL::Segment_2<Kernel>  Segment_2; 
  //typedef CGAL::Triangle_2<Kernel> Triangle_2; 
  typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
  typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
  typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
  typedef CGAL::Exact_intersections_tag Itag;
  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
    CDT_2;
  typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;

  // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
  // Plane of triangle A
  Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
  // Insert triangle into vertices
  typename CDT_plus_2::Vertex_handle corners[3];
  typedef size_t Index;
  for(Index i = 0;i<3;i++)
  {
    const Point_3 & p3 = A.vertex(i);
    const Point_2 & p2 = P.to_2d(p3);
    typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2);
    corners[i] = corner;
  }
  // Insert triangle edges as constraints
  for(Index i = 0;i<3;i++)
  {
    cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
  }
  // Insert constraints for intersection objects
  for( const auto & obj : A_objects_3)
  {
    if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
    {
      // Add segment constraint
      cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
    }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
    {
      // Add point
      cdt.insert(P.to_2d(*ipoint));
    } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
    {
      // Add 3 segment constraints
      cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
      cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
      cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
    } else if(const std::vector<Point_3 > *polyp = 
        CGAL::object_cast< std::vector<Point_3 > >(&obj))
    {
      //cerr<<REDRUM("Poly...")<<endl;
      const std::vector<Point_3 > & poly = *polyp;
      const Index m = poly.size();
      assert(m>=2);
      for(Index p = 0;p<m;p++)
      {
        const Index np = (p+1)%m;
        cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
      }
    }else
    {
      cerr<<REDRUM("What is this object?!")<<endl;
      assert(false);
    }
  }
}