//#####################################################################
// Copyright 2002-2007, Ronald Fedkiw, Eran Guendelman, Geoffrey Irving, Avi Robinson-Mosher, Craig Schroeder, Jerry Talton.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class ORIENTED_BOX
//##################################################################### 
#include <Core/Basic_Geometry/ORIENTED_BOX.h>
#include <Core/Auto_Diff/AUTO_DIFF.h>
#include <Core/Auto_Diff/AUTO_HESS.h>
#include <Core/Basic_Geometry/RANGE_TESSELLATION.h>
#include <Core/Basic_Geometry/RAY.h>
#include <Core/Basic_Geometry/RAY_HIT.h>
#include <Core/Basic_Geometry/SPHERE.h>
#include <Core/Implicit_Objects/INTERSECTION_HELPERS.h>
#include <Core/Log/LOG.h>
#include <Core/Matrices/FRAME.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Random_Numbers/RANDOM_NUMBERS.h>
#include <Core/Read_Write/READ_WRITE.h>
namespace PhysBAM{
//#####################################################################
// Function Intersection_Helper
//#####################################################################
template<class T,class T_BOX> static bool Intersection_Helper(const ORIENTED_BOX<VECTOR<T,1> >& self,const T_BOX& box,const VECTOR<T,1>& u,const VECTOR<T,1>& v){PHYSBAM_NOT_IMPLEMENTED();}
template<class T,class T_BOX> static bool Intersection_Helper(const ORIENTED_BOX<VECTOR<T,2> >& self,const T_BOX& box,const VECTOR<T,2>& u,const VECTOR<T,2>& v){return false;}
template<class T,class T_BOX> static bool Intersection_Helper(const ORIENTED_BOX<VECTOR<T,3> >& self,const T_BOX& box,const VECTOR<T,3>& u,const VECTOR<T,3>& v)
{
    return self.Separating_Test(box,u.Cross(v));
}
//#####################################################################
// Function Intersection
//#####################################################################
template<class TV> bool ORIENTED_BOX<TV>::
Intersection(const ORIENTED_BOX& box) const
{
    for(int i=0;i<d;i++) if(Separating_Test(box,edges.Column(i)) || Separating_Test(box,box.edges.Column(i))) return false;
    for(int i=0;i<d;i++) for(int j=0;j<d;j++) if(Intersection_Helper(*this,box,edges.Column(i),box.edges.Column(j))) return false;
    return true; // otherwise
}
//#####################################################################
// Function Intersection
//#####################################################################
template<class TV> bool ORIENTED_BOX<TV>::
Intersection(const RANGE<TV>& box) const
{
    for(int j=0;j<d;j++){
        T line_min=corner(j),line_max=corner(j);
        for(int i=0;i<d;i++) if(edges.Column(i)(j)>0) line_max+=edges.Column(i)(j);else line_min+=edges.Column(i)(j);
        if(line_max<box.min_corner(j) || line_min>box.max_corner(j)) return false;}
    for(int i=0;i<d;i++) if(Separating_Test(box,edges.Column(i))) return false;
    if(d==3) for(int j=0;j<d;j++){
        TV box_edge;box_edge(j)=box.max_corner(j)-box.min_corner(j);
        for(int i=0;i<d;i++) if(Intersection_Helper(*this,box,edges.Column(i),box_edge)) return false;}
    return true; // otherwise
}
//#####################################################################
// Function Separating_Test
//#####################################################################
template<class TV> inline  bool ORIENTED_BOX<TV>::
Separating_Test(const ORIENTED_BOX& box,const TV& direction) const
{
    T min1,max1;Project_Points_Onto_Line(direction,min1,max1);
    T min2,max2;box.Project_Points_Onto_Line(direction,min2,max2);
    if(max2<min1 || min2>max1) return true;else return false;
}
//#####################################################################
// Function Separating_Test
//#####################################################################
template<class TV> inline bool ORIENTED_BOX<TV>::
Separating_Test(const RANGE<TV>& box,const TV& direction) const
{
    T min1,max1;Project_Points_Onto_Line(direction,min1,max1);
    T min2,max2;box.Project_Points_Onto_Line(direction,min2,max2);
    if(max2<min1 || min2>max1) return true;else return false;
}
//#####################################################################
// Function Project_Points_Onto_Line
//#####################################################################
template<class TV> inline void ORIENTED_BOX<TV>::
Project_Points_Onto_Line(const TV& direction,T& line_min,T& line_max) const
{
    line_min=line_max=direction.Dot(corner);
    TV e=edges.Transpose_Times(direction);
    for(int i=0;i<d;i++) if(e(i)>0) line_max+=e(i);else line_min+=e(i);
}
//#####################################################################
// Function Signed_Distance
//#####################################################################
template<class TV> typename TV::SCALAR ORIENTED_BOX<TV>::
Signed_Distance(const TV& X) const
{
    TV lengths;
    for(int i=0;i<TV::m;i++) lengths(i)=edges.Column(i).Magnitude();
    if(lengths.Contains(0)) PHYSBAM_NOT_IMPLEMENTED();
    TV phi=abs(edges.Transpose_Times(X-Center()))/lengths-(T).5*lengths;
    if(!phi.All_Less_Equal(TV())) return phi.Componentwise_Max(TV()).Magnitude();
    return phi.Max();
}
//#####################################################################
// Function Normal
//#####################################################################
template<class TV> TV ORIENTED_BOX<TV>::
Normal(const TV& X) const
{
    TV lengths;
    for(int i=0;i<TV::m;i++) lengths(i)=edges.Column(i).Magnitude();
    if(lengths.Contains(0)) PHYSBAM_NOT_IMPLEMENTED();
    MATRIX<T,TV::m> M=DIAGONAL_MATRIX<T,TV::m>(lengths).Inverse()*edges.Transposed();
    AUTO_DIFF<TV,TV> t(M*X,M),phi=abs(t-M*Center())-(T).5*lengths;
    if(phi.x.All_Less_Equal(TV())) return max(phi).dx;
    for(int i=0;i<TV::m;i++) if(phi.x(i)<0) phi.Set_Entry(i,AUTO_DIFF<T,TV>());
    return phi.Magnitude().dx;
}
//#####################################################################
// Function Hessian
//#####################################################################
template<class TV> SYMMETRIC_MATRIX<typename TV::SCALAR,TV::m> ORIENTED_BOX<TV>::
Hessian(const TV& X) const
{
    TV lengths;
    for(int i=0;i<TV::m;i++) lengths(i)=edges.Column(i).Magnitude();
    if(lengths.Contains(0)) PHYSBAM_NOT_IMPLEMENTED();
    MATRIX<T,TV::m> M=DIAGONAL_MATRIX<T,TV::m>(lengths).Inverse()*edges.Transposed();
    AUTO_HESS<TV,TV> t(M*X,M),phi=abs(t-M*Center())-(T).5*lengths;
    if(phi.x.All_Less_Equal(TV())) return max(phi).ddx;
    for(int i=0;i<TV::m;i++) if(phi.x(i)<0) phi.Set_Entry(i,AUTO_HESS<T,TV>());
    return phi.Magnitude().ddx;
}
//#####################################################################
// Function Name
//#####################################################################
template<class TV> std::string ORIENTED_BOX<TV>::
Name()
{   
    return LOG::sprintf("ORIENTED_BOX<VECTOR<T,%d>",d);
}
//#####################################################################
// Function Lazy_Inside
//#####################################################################
template<class TV> bool ORIENTED_BOX<TV>::
Lazy_Inside(const TV &location) const
{
    TV vec=location-corner,edge_projection=edges.Transpose_Times(vec);
    // TODO: you presently cannot be inside a degenerate box
    for(int i=0;i<d;i++)
        if(edge_projection(i)<0 || edge_projection(i)>edges.Column(i).Magnitude_Squared() || edges.Column(i).Magnitude_Squared()==0)
            return false;
    return true;
}
namespace
{
template<class T,class E> void
Generate_Unit_Direction(const E& edges,VECTOR<T,1>& v,int i)
{
    v=VECTOR<T,1>(edges(1,1)<0?-1:1);
}
template<class T,class E> void
Generate_Unit_Direction(const E& edges,VECTOR<T,2>& v,int i)
{
    v=edges.Column(i);
    if(!v.Normalize()) v=edges.Column(1-i).Perpendicular().Normalized();
}
template<class T,class E> void
Generate_Unit_Direction(const E& edges,VECTOR<T,3>& v,int i)
{
    v=edges.Column(i);
    if(!v.Normalize()) v=edges.Column(i==0?1:0).Cross(edges.Column(i==2?1:2)).Normalized();
}
}
//#####################################################################
// Function Thickened
//#####################################################################
template<class TV> ORIENTED_BOX<TV> ORIENTED_BOX<TV>::
Thickened(const T thickness) const
{
    ORIENTED_BOX box(*this);
    TV u;
    for(int i=0;i<d;i++)
    {
        Generate_Unit_Direction(edges,u,i);
        u*=thickness;
        box.corner-=u;
        box.edges.Set_Column(i,box.edges.Column(i)+(u+u));
    }
    return box;
}
//#####################################################################
// Function Volume
//#####################################################################
template<class TV> typename TV::SCALAR ORIENTED_BOX<TV>::
Volume() const
{
    return edges.Determinant();
}
//#####################################################################
// Function Read
//#####################################################################
template<class TV> template<class RW> void ORIENTED_BOX<TV>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    Read_Binary_Group(input,corner,edges);
}
//#####################################################################
// Function Write
//#####################################################################
template<class TV> template<class RW> void ORIENTED_BOX<TV>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Write_Binary_Group(output,corner,edges);
}
//#####################################################################
// Function Fill_Uniform
//#####################################################################
template<class TV> void ORIENTED_BOX<TV>::
Fill_Uniform(RANDOM_NUMBERS<T>& rand,const RANGE<TV>& box)
{
    SPHERE<TV> s;
    rand.Fill_Uniform(s,box);
    TV dir;
    rand.Fill_Uniform(dir,0,1);
    dir=dir.Normalized()*s.radius;
    ROTATION<TV> rot;
    rand.Fill_Uniform(rot);
    *this=ORIENTED_BOX<TV>(RANGE<TV>(-dir,dir),FRAME<TV>(s.center,rot));
}
//#####################################################################
// Function Scaled
//#####################################################################
template<class T,class TV> ORIENTED_BOX<TV>
Scaled(const ORIENTED_BOX<TV>& b,const TV& center,T scale)
{
    return ORIENTED_BOX<TV>((b.corner-center)*scale+center,scale*b.edges);
}
//#####################################################################
// Function Transformed
//#####################################################################
template<class TV> ORIENTED_BOX<TV>
Transformed(const ORIENTED_BOX<TV>& b,const FRAME<TV>& f)
{
    return ORIENTED_BOX<TV>(f*b.corner,f.r.Rotation_Matrix()*b.edges);
}
//#####################################################################
// Function Generate_Triangles
//#####################################################################
template<class T> TRIANGULATED_SURFACE<T>* Generate_Triangles(const ORIENTED_BOX<VECTOR<T,3> >& box,VECTOR<int,3> res)
{
    typedef VECTOR<T,3> TV;
    MATRIX<T,3> directions=box.edges;TV lengths;
    for(int i=0;i<3;i++) lengths[i]=directions.Column(i).Normalize();
    RANGE<TV> aligned_box=RANGE<TV>::Unit_Box();
    TRIANGULATED_SURFACE<T>* ts=Generate_Triangles(aligned_box,res);
    for(auto&x:ts->particles.X)
        x=box.corner+box.edges*x;
    return ts;
}
//#####################################################################
// Function Intersects
//#####################################################################
template<class TV> RAY_HIT<typename TV::SCALAR>
Intersects(const RAY<TV>& ray,const ORIENTED_BOX<TV>& box,
    typename TV::SCALAR isocontour)
{
    typedef typename TV::SCALAR T;
    TV A=box.edges.Inverse_Times(ray.endpoint-box.corner);
    TV B=box.edges.Inverse_Times(ray.direction);
    T blen=B.Normalize();
    RAY<TV> xform_ray(A,B,ray_normalized);
    RAY_HIT<T> hit=Intersects(xform_ray,RANGE<TV>::Unit_Box(),isocontour*blen);
    if(hit.Hit()) hit.dist/=blen;
    return hit;
}
//#####################################################################
// Function Fuzzy_Intersects
//#####################################################################
template<class T> RAY_HIT<T>
Fuzzy_Intersects(const RAY<VECTOR<T,2> >& ray,
    const ORIENTED_BOX<VECTOR<T,2> >& box,const T segment_intersect_epsilon)
{
    RAY_HIT<T> hit;
    for(int i=0;i<2;i++) hit=hit.Best(Fuzzy_Intersects(ray,SEGMENT_2D<T>(box.corner,box.corner+box.edges.Column(i)),segment_intersect_epsilon));
    for(int i=0;i<2;i++) hit=hit.Best(Fuzzy_Intersects(ray,SEGMENT_2D<T>(box.corner+box.edges.Column(i),box.corner+box.edges.Column(0)+box.edges.Column(1)),segment_intersect_epsilon));
    return hit;
}
//#####################################################################
// Function All_Intersections
//#####################################################################
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,
    const ORIENTED_BOX<TV>& box,const T isocontour)
{
    auto iv=Intersection_Interval(ray,box,isocontour);
    hits=iv.Array_View(0,Actual_Length(iv));
}
//#####################################################################
// Function Intersection_Interval
//#####################################################################
template<class TV> VECTOR<RAY_HIT<typename TV::SCALAR>,2>
Intersection_Interval(const RAY<TV>& ray,const ORIENTED_BOX<TV>& box,
    typename TV::SCALAR isocontour)
{
    typedef typename TV::SCALAR T;
    TV A=box.edges.Inverse_Times(ray.endpoint-box.corner);
    TV B=box.edges.Inverse_Times(ray.direction);
    T blen=B.Normalize();
    RAY<TV> xform_ray(A,B,ray_normalized);
    auto iv=Intersection_Interval(xform_ray,RANGE<TV>::Unit_Box(),isocontour*blen);
    int n=Actual_Length(iv);
    for(int i=0;i<n;i++) iv(i).dist/=blen;
    return iv;
}
//#####################################################################
template RAY_HIT<float> Fuzzy_Intersects(const RAY<VECTOR<float,2> >&,const ORIENTED_BOX<VECTOR<float,2> >&,const float);
template RAY_HIT<double> Fuzzy_Intersects(const RAY<VECTOR<double,2> >&,const ORIENTED_BOX<VECTOR<double,2> >&,const double);
//#####################################################################
#define INSTANTIATION_HELPER(T,d) \
    template std::string ORIENTED_BOX<VECTOR<T,d> >::Name(); \
    template bool ORIENTED_BOX<VECTOR<T,d> >::Intersection(const ORIENTED_BOX<VECTOR<T,d> >& box) const; \
    template bool ORIENTED_BOX<VECTOR<T,d> >::Intersection(const RANGE<VECTOR<T,d> >& box) const; \
    template bool ORIENTED_BOX<VECTOR<T,d> >::Separating_Test(const ORIENTED_BOX& box,const VECTOR<T,d> & direction) const; \
    template bool ORIENTED_BOX<VECTOR<T,d> >::Separating_Test(const RANGE<VECTOR<T,d> >& box,const VECTOR<T,d> & direction) const; \
    template void ORIENTED_BOX<VECTOR<T,d> >::Project_Points_Onto_Line(const VECTOR<T,d> & direction,T& line_min,T& line_max) const; \
    template T ORIENTED_BOX<VECTOR<T,d> >::Signed_Distance(const VECTOR<T,d>& X) const; \
    template SYMMETRIC_MATRIX<T,d> ORIENTED_BOX<VECTOR<T,d> >::Hessian(const VECTOR<T,d>&) const; \
    template VECTOR<T,d> ORIENTED_BOX<VECTOR<T,d> >::Normal(const VECTOR<T,d>& X) const;

INSTANTIATION_HELPER(float,1);
INSTANTIATION_HELPER(float,2);
INSTANTIATION_HELPER(float,3);
INSTANTIATION_HELPER(double,1);
INSTANTIATION_HELPER(double,2);
INSTANTIATION_HELPER(double,3);
template bool ORIENTED_BOX<VECTOR<double,1> >::Lazy_Inside(VECTOR<double,1> const&) const;
template ORIENTED_BOX<VECTOR<double,1> > ORIENTED_BOX<VECTOR<double,1> >::Thickened(double) const;
template bool ORIENTED_BOX<VECTOR<double,2> >::Lazy_Inside(VECTOR<double,2> const&) const;
template ORIENTED_BOX<VECTOR<double,2> > ORIENTED_BOX<VECTOR<double,2> >::Thickened(double) const;
template bool ORIENTED_BOX<VECTOR<double,3> >::Lazy_Inside(VECTOR<double,3> const&) const;
template ORIENTED_BOX<VECTOR<double,3> > ORIENTED_BOX<VECTOR<double,3> >::Thickened(double) const;
template bool ORIENTED_BOX<VECTOR<float,1> >::Lazy_Inside(VECTOR<float,1> const&) const;
template ORIENTED_BOX<VECTOR<float,1> > ORIENTED_BOX<VECTOR<float,1> >::Thickened(float) const;
template bool ORIENTED_BOX<VECTOR<float,2> >::Lazy_Inside(VECTOR<float,2> const&) const;
template ORIENTED_BOX<VECTOR<float,2> > ORIENTED_BOX<VECTOR<float,2> >::Thickened(float) const;
template bool ORIENTED_BOX<VECTOR<float,3> >::Lazy_Inside(VECTOR<float,3> const&) const;
template ORIENTED_BOX<VECTOR<float,3> > ORIENTED_BOX<VECTOR<float,3> >::Thickened(float) const;
template float ORIENTED_BOX<VECTOR<float,3> >::Volume() const;
template double ORIENTED_BOX<VECTOR<double,3> >::Volume() const;
template ORIENTED_BOX<VECTOR<double,3> > Scaled<double,VECTOR<double,3> >(ORIENTED_BOX<VECTOR<double,3> > const&,VECTOR<double,3> const&,double);
template ORIENTED_BOX<VECTOR<double,3> > Transformed<VECTOR<double,3> >(ORIENTED_BOX<VECTOR<double,3> > const&,FRAME<VECTOR<double,3> > const&);
template ORIENTED_BOX<VECTOR<float,3> > Scaled<float,VECTOR<float,3> >(ORIENTED_BOX<VECTOR<float,3> > const&,VECTOR<float,3> const&,float);
template ORIENTED_BOX<VECTOR<float,3> > Transformed<VECTOR<float,3> >(ORIENTED_BOX<VECTOR<float,3> > const&,FRAME<VECTOR<float,3> > const&);
template MESH_OBJECT<VECTOR<double,3>,2>* Generate_Triangles<double>(ORIENTED_BOX<VECTOR<double,3> > const&,VECTOR<int,3>);
template MESH_OBJECT<VECTOR<float,3>,2>* Generate_Triangles<float>(ORIENTED_BOX<VECTOR<float,3> > const&,VECTOR<int,3>);
template ORIENTED_BOX<VECTOR<double,2> > Scaled<double,VECTOR<double,2> >(ORIENTED_BOX<VECTOR<double,2> > const&,VECTOR<double,2> const&,double);
template ORIENTED_BOX<VECTOR<double,2> > Transformed<VECTOR<double,2> >(ORIENTED_BOX<VECTOR<double,2> > const&,FRAME<VECTOR<double,2> > const&);
template RAY_HIT<double> Intersects<VECTOR<double,3> >(RAY<VECTOR<double,3> > const&,ORIENTED_BOX<VECTOR<double,3> > const&,double);
template RAY_HIT<float> Intersects<VECTOR<float,3> >(RAY<VECTOR<float,3> > const&,ORIENTED_BOX<VECTOR<float,3> > const&,float);
template RAY_HIT<double> Intersects<VECTOR<double,2> >(RAY<VECTOR<double,2> > const&,ORIENTED_BOX<VECTOR<double,2> > const&,double);
template RAY_HIT<float> Intersects<VECTOR<float,2> >(RAY<VECTOR<float,2> > const&,ORIENTED_BOX<VECTOR<float,2> > const&,float);
template void All_Intersections<VECTOR<double,2>,double>(ARRAY<RAY_HIT<double>,int>&,RAY<VECTOR<double,2> > const&,ORIENTED_BOX<VECTOR<double,2> > const&,double);
template void All_Intersections<VECTOR<double,3>,double>(ARRAY<RAY_HIT<double>,int>&,RAY<VECTOR<double,3> > const&,ORIENTED_BOX<VECTOR<double,3> > const&,double);
template void All_Intersections<VECTOR<float,2>,float>(ARRAY<RAY_HIT<float>,int>&,RAY<VECTOR<float,2> > const&,ORIENTED_BOX<VECTOR<float,2> > const&,float);
template void All_Intersections<VECTOR<float,3>,float>(ARRAY<RAY_HIT<float>,int>&,RAY<VECTOR<float,3> > const&,ORIENTED_BOX<VECTOR<float,3> > const&,float);
template void ORIENTED_BOX<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<char>&);
template void ORIENTED_BOX<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<double>&);
template void ORIENTED_BOX<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<float>&);
template void ORIENTED_BOX<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<char>&) const;
template void ORIENTED_BOX<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<double>&) const;
template void ORIENTED_BOX<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<float>&) const;
template void ORIENTED_BOX<VECTOR<double,1> >::Fill_Uniform(RANDOM_NUMBERS<double>&,RANGE<VECTOR<double,1> > const&);
template void ORIENTED_BOX<VECTOR<double,2> >::Fill_Uniform(RANDOM_NUMBERS<double>&,RANGE<VECTOR<double,2> > const&);
template void ORIENTED_BOX<VECTOR<double,3> >::Fill_Uniform(RANDOM_NUMBERS<double>&,RANGE<VECTOR<double,3> > const&);
template void ORIENTED_BOX<VECTOR<float,1> >::Fill_Uniform(RANDOM_NUMBERS<float>&,RANGE<VECTOR<float,1> > const&);
template void ORIENTED_BOX<VECTOR<float,2> >::Fill_Uniform(RANDOM_NUMBERS<float>&,RANGE<VECTOR<float,2> > const&);
template void ORIENTED_BOX<VECTOR<float,3> >::Fill_Uniform(RANDOM_NUMBERS<float>&,RANGE<VECTOR<float,3> > const&);
}
