text: //==================================================================================================
  // Written in 2016 by Peter Shirley <ptrshrl@gmail.com>
  //
  // To the extent possible under law, the author(s) have dedicated all copyright and related and
  // neighboring rights to this software to the public domain worldwide. This software is distributed
  // without any warranty.
  //
  // You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along
  // with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
  //==================================================================================================
  
  #ifndef AARECTH
  #define AARECTH
  
  #include "hitable.h"
  
  class xy_rect: public hitable  {
      public:
          xy_rect() {}
          xy_rect(float _x0, float _x1, float _y0, float _y1, float _k, material *mat) : x0(_x0), x1(_x1), y0(_y0), y1(_y1), k(_k), mp(mat) {};
          virtual bool hit(const ray& r, float t0, float t1, hit_record& rec) const;
          virtual bool bounding_box(float t0, float t1, aabb& box) const {
                 box =  aabb(vec3(x0,y0, k-0.0001), vec3(x1, y1, k+0.0001));
                 return true; }
          material  *mp;
          float x0, x1, y0, y1, k;
  };
  
  class xz_rect: public hitable  {
      public:
          xz_rect() {}
          xz_rect(float _x0, float _x1, float _z0, float _z1, float _k, material *mat) : x0(_x0), x1(_x1), z0(_z0), z1(_z1), k(_k), mp(mat) {};
          virtual bool hit(const ray& r, float t0, float t1, hit_record& rec) const;
          virtual bool bounding_box(float t0, float t1, aabb& box) const {
              box =  aabb(vec3(x0,k-0.0001,z0), vec3(x1, k+0.0001, z1));
              return true; 
          }
          virtual float  pdf_value(const vec3& o, const vec3& v) const {
              hit_record rec;
              if (this->hit(ray(o, v), 0.001, FLT_MAX, rec)) {
                  float area = (x1-x0)*(z1-z0);
                  float distance_squared = rec.t * rec.t * v.squared_length();
                  float cosine = fabs(dot(v, rec.normal) / v.length());
                  return  distance_squared / (cosine * area);
              }
              else
                  return 0;
          }
          virtual vec3 random(const vec3& o) const { 
              vec3 random_point = vec3(x0 + drand48()*(x1-x0), k,  z0 + drand48()*(z1-z0)); 
              return random_point - o;
          }
          material  *mp;
          float x0, x1, z0, z1, k;
  };
  
  class yz_rect: public hitable  {
      public:
          yz_rect() {}
          yz_rect(float _y0, float _y1, float _z0, float _z1, float _k, material *mat) : y0(_y0), y1(_y1), z0(_z0), z1(_z1), k(_k), mp(mat) {};
          virtual bool hit(const ray& r, float t0, float t1, hit_record& rec) const;
          virtual bool bounding_box(float t0, float t1, aabb& box) const {
                 box =  aabb(vec3(k-0.0001, y0, z0), vec3(k+0.0001, y1, z1));
                 return true; }
          material  *mp;
          float y0, y1, z0, z1, k;
  };
  
  
  
  
  bool xy_rect::hit(const ray& r, float t0, float t1, hit_record& rec) const {
      float t = (k-r.origin().z()) / r.direction().z();
      if (t < t0 || t > t1)
          return false;
      float x = r.origin().x() + t*r.direction().x();
      float y = r.origin().y() + t*r.direction().y();
      if (x < x0 || x > x1 || y < y0 || y > y1) 
          return false;
      rec.u = (x-x0)/(x1-x0);
      rec.v = (y-y0)/(y1-y0); 
      rec.t = t;
      rec.mat_ptr = mp;
      rec.p = r.point_at_parameter(t);
      rec.normal = vec3(0, 0, 1);
      return true;
  }
  
  
  bool xz_rect::hit(const ray& r, float t0, float t1, hit_record& rec) const {
      float t = (k-r.origin().y()) / r.direction().y();
      if (t < t0 || t > t1)
          return false;
      float x = r.origin().x() + t*r.direction().x();
      float z = r.origin().z() + t*r.direction().z();
      if (x < x0 || x > x1 || z < z0 || z > z1) 
          return false;
      rec.u = (x-x0)/(x1-x0);
      rec.v = (z-z0)/(z1-z0); 
      rec.t = t;
      rec.mat_ptr = mp;
      rec.p = r.point_at_parameter(t);
      rec.normal = vec3(0, 1, 0);
      return true;
  }
  
  bool yz_rect::hit(const ray& r, float t0, float t1, hit_record& rec) const {
      float t = (k-r.origin().x()) / r.direction().x();
      if (t < t0 || t > t1)
          return false;
      float y = r.origin().y() + t*r.direction().y();
      float z = r.origin().z() + t*r.direction().z();
      if (y < y0 || y > y1 || z < z0 || z > z1) 
          return false;
      rec.u = (y-y0)/(y1-y0);
      rec.v = (z-z0)/(z1-z0); 
      rec.t = t;
      rec.mat_ptr = mp;
      rec.p = r.point_at_parameter(t);
      rec.normal = vec3(1, 0, 0);
      return true;
  }
  
  #endif
  