//#####################################################################
// Copyright 2002-2007, Ronald Fedkiw, Geoffrey Irving, Neil Molino, Jonathan Su.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class CYLINDER
//##################################################################### 
#ifndef __CYLINDER__
#define __CYLINDER__

#include <Core/Basic_Geometry/PLANE.h>
namespace PhysBAM{

template<class T>
class CYLINDER
{
    typedef VECTOR<T,3> TV;
public:
    typedef TV VECTOR_T;

    T height,radius;
    PLANE<T> plane1,plane2; // plane2 is height units behind circle

    CYLINDER()
        :height(1),radius(1),plane2(plane1.x0-height*plane1.normal,-plane1.normal)
    {}

    CYLINDER(const TV& point1,const TV& point2,const T radius)
        :radius(radius)
    {
        Set_Endpoints(point1,point2);
    }

    void Set_Height(const T height_input)
    {height=height_input;plane2.x0=plane1.x0-height*plane1.normal;}

    void Set_Endpoints(const TV& point1,const TV& point2)
    {TV height_vector=point1-point2;height=height_vector.Normalize();
    plane1.x0=point1;plane1.normal=height_vector;
    plane2.x0=point2;plane2.normal=-plane1.normal;}

    static std::string Name() 
    {return "CYLINDER<T>";}

//#####################################################################
    TV Normal(const TV& location) const;
    TV Normal(const TV& location,const int aggregate) const;
    SYMMETRIC_MATRIX<T,3> Hessian(const TV& X) const;
    bool Inside(const TV& location,const T thickness_over_two) const;
    bool Lazy_Inside(const TV& location) const;
    bool Outside(const TV& location,const T thickness_over_two) const;
    bool Lazy_Outside(const TV& location) const;
    bool Boundary(const TV& location,const T thickness_over_two) const;
    TV Surface(const TV& location) const;
    T Signed_Distance(const TV& location) const;
    RANGE<TV> Bounding_Box() const;
    T Volume() const;
    template<class RW> void Read(UNTYPED_ISTREAM<RW>& input);
    template<class RW> void Write(UNTYPED_OSTREAM<RW>& output) const;
    void Fill_Uniform(RANDOM_NUMBERS<T>& rand,const RANGE<TV>& box);
//#####################################################################
};   
template<class T> class RAY_HIT;
template<class TV> class RAY;

template<class T,class TV> CYLINDER<T> Scaled(const CYLINDER<T>& b,const TV& center,T scale);
template<class T,class TV> CYLINDER<T> Transformed(const CYLINDER<T>& b,const FRAME<TV>& f);
template<class T> TRIANGULATED_SURFACE<T>*
Generate_Triangles(const CYLINDER<T>& cylinder,const int resolution_height=4,const int resolution_radius=16);
template<class T> RAY_HIT<T> Intersects(const RAY<VECTOR<T,3> >& ray,const CYLINDER<T>& cylinder,const T isocontour=0);
template<class T> VECTOR<RAY_HIT<T>,2>
Intersection_Interval_Infinite(const RAY<VECTOR<T,3> >& ray,const CYLINDER<T>& cylinder,T isocontour=0);
template<class T> VECTOR<RAY_HIT<T>,6>
Intersection_Interval(const RAY<VECTOR<T,3> >& ray,const CYLINDER<T>& cylinder,T isocontour=0);
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const CYLINDER<T>& cylinder,const T isocontour=0);
}
#endif
