/*******************************************************************************
+
+  LEDA 7.2.2  
+
+
+  _d3_rat_ray.c
+
+
+  Copyright (c) 1995-2025
+  by Algorithmic Solutions Software GmbH
+  All rights reserved.
+ 
*******************************************************************************/


#include <LEDA/geo/d3_rat_ray.h>
#include <LEDA/geo/d3_rat_plane.h>
#include <LEDA/geo/d3_rat_line.h>

//----------------------------------------------
// d3_rat_ray (1999)
//----------------------------------------------


LEDA_BEGIN_NAMESPACE

atomic_counter d3_rat_ray_rep::id_counter(0);
   
d3_rat_ray_rep::d3_rat_ray_rep(const d3_rat_segment& s2) : seg(s2)
{
 if (s2.is_trivial()) LEDA_EXCEPTION(1,"d3_rat_ray_rep: constructor got trivial segment");
 id=++id_counter;
}

d3_rat_ray::d3_rat_ray(const d3_rat_point& p1,const d3_rat_point& p2)
{
 PTR = new d3_rat_ray_rep(d3_rat_segment(p1,p2));
}

d3_rat_ray::d3_rat_ray(const list<d3_rat_point>& L)
{
 if (L.size() < 2) LEDA_EXCEPTION(1,"d3_rat_ray: constructor: list has fewer than 2 elements.");
 d3_rat_point p1,p2;
 p1= L[L[0]]; p2=L[L[1]];
 PTR = new d3_rat_ray_rep(d3_rat_segment(p1,p2));
}

d3_rat_ray::d3_rat_ray(const d3_rat_segment& s)
{
 PTR = new d3_rat_ray_rep(s);
}

d3_rat_ray::d3_rat_ray()
{
 PTR = new d3_rat_ray_rep(d3_rat_segment(d3_rat_point(0,0,0),d3_rat_point(1,1,1)));
}

bool d3_rat_ray::contains(const d3_rat_point& p) const
{
 d3_rat_point p1=point1();
 d3_rat_point p2=point2();
 if (! collinear(p,p1,p2)) return false;
 
 // collinear ...
 if (in_xyz(p)) return true;
 return false; 
}

bool d3_rat_ray::contains(const d3_rat_segment& s) const
{
 d3_rat_point p1 = s.source();
 d3_rat_point p2 = s.target();
 
 if (contains(p1) && contains(p2)) return true;
 else return false;
}

bool d3_rat_ray::in_xyz(const d3_rat_point& p) const
{
 d3_rat_point p1=point1();
 d3_rat_point p2=point2();
 
 int c1,c2,c3;
 int d1,d2,d3;
 
 c1 = d3_rat_point::cmp_x(p1,p2);
 d1 = d3_rat_point::cmp_x(p1,p);
 if (d1==0 || c1==d1) ; else return false;
 
 c2 = d3_rat_point::cmp_y(p1,p2);
 d2 = d3_rat_point::cmp_y(p1,p);
 if (d2==0 || c2==d2) ; else return false;
 
 c3 = d3_rat_point::cmp_z(p1,p2);
 d3 = d3_rat_point::cmp_z(p1,p);
 if (d3==0 || c3==d3) ; else return false; 
 
 return true;
}

d3_rat_point d3_rat_ray::source() const
{
 d3_rat_segment s= ptr()->seg;
 return s.point1();
}

d3_rat_point d3_rat_ray::point1() const
{
 d3_rat_segment s= ptr()->seg;
 return s.point1();
}

d3_rat_point d3_rat_ray::point2() const
{
 d3_rat_segment s= ptr()->seg;
 return s.point2();
}

d3_rat_segment d3_rat_ray::seg() const
{
 d3_rat_segment s= ptr()->seg;
 return s;
}
 
bool d3_rat_ray::x_equal() const
{
 d3_rat_point p1=point1();
 d3_rat_point p2=point2();
 return (p1.xcoord() == p2.xcoord());
}

bool d3_rat_ray::y_equal() const
{
 d3_rat_point p1=point1();
 d3_rat_point p2=point2();
 return (p1.ycoord() == p2.ycoord());
}

bool d3_rat_ray::z_equal() const
{
 d3_rat_point p1=point1();
 d3_rat_point p2=point2();
 return (p1.zcoord() == p2.zcoord());
}

bool d3_rat_ray::xy_equal() const
{ return (x_equal() && y_equal()); }

bool d3_rat_ray::xz_equal() const
{  return (x_equal() && z_equal()); }

bool d3_rat_ray::yz_equal() const
{ return (y_equal() && z_equal()); }

bool d3_rat_ray::intersection(const d3_rat_segment& s, d3_rat_point& inter) const
{
  d3_rat_line l1(s);
  d3_rat_line l2(point1(),point2());
  d3_rat_point pt;
  
  bool i = l1.intersection(l2,pt);
  if (! i) return false;
  
  if (s.contains(pt) && contains(pt)) { inter= pt; return true; }
  else return false;
}
  
bool d3_rat_ray::intersection(const d3_rat_ray& r, d3_rat_point& inter) const
{
  d3_rat_line l1(r.point1(),r.point2());
  d3_rat_line l2(point1(),point2());
  d3_rat_point pt;
  
  bool i = l1.intersection(l2,pt);
  if (! i) return false;
  
  if (r.contains(pt) && contains(pt)) { inter= pt; return true; }

  else return false;
}

bool d3_rat_ray::project_xy(rat_ray& m) const 
{
 d3_rat_segment ds= seg();
 rat_segment spr= ds.project_xy();
 if (spr.is_trivial()) return false;
 else { m=rat_ray(spr); return true; }
}

bool d3_rat_ray::project_xz(rat_ray& m) const 
{
 d3_rat_segment ds= seg();
 rat_segment spr= ds.project_xz();
 if (spr.is_trivial()) return false;
 else { m=rat_ray(spr); return true; }
}

bool d3_rat_ray::project_yz(rat_ray& m) const 
{
 d3_rat_segment ds= seg();
 rat_segment spr= ds.project_yz();
 if (spr.is_trivial()) return false;
 else { m=rat_ray(spr); return true; }
}

bool d3_rat_ray::project(const d3_rat_point& pt, const d3_rat_point& qt, const d3_rat_point& vt, d3_rat_ray& m) const
{
 d3_rat_plane p(pt,qt,vt);
 rat_vector v1=p.normal_project(point1());
 rat_vector v2=p.normal_project(point2());
 d3_rat_point pn1= point1()+v1, pn2= point2()+v2;
 if (pn1==pn2) return false;
 m=d3_rat_ray(pn1,pn2);
 return true;
}

d3_rat_ray d3_rat_ray::reverse() const
{
  d3_rat_point p1 = point1();
  d3_rat_point p2 = p1 + (p1 - point2());
  
  return d3_rat_ray(p1,p2);
}

d3_rat_ray d3_rat_ray::translate(const rat_vector& v) const
{
  d3_rat_point p1 = point1();
  d3_rat_point p2 = point2();
  
  return d3_rat_ray(p1.translate(v),p2.translate(v));
}

d3_rat_ray d3_rat_ray::translate(rational dx, rational dy, rational dz) const
{
  d3_rat_point p1 = point1();
  d3_rat_point p2 = point2();
  
  return d3_rat_ray(p1.translate(dx,dy,dz),p2.translate(dx,dy,dz));
}

d3_rat_ray d3_rat_ray::reflect(const d3_rat_point& pt, const d3_rat_point& qt, const d3_rat_point& vt) const
{
 d3_rat_plane p(pt,qt,vt);
 return d3_rat_ray(p.reflect_point(point1()),p.reflect_point(point2()));
}

d3_rat_ray d3_rat_ray::reflect(const d3_rat_point& p) const
{
 d3_rat_segment ds= seg().reflect(p);
 return d3_rat_ray(ds); 
}

rat_vector d3_rat_ray::to_vector() const
{
 d3_rat_segment seg= ptr()->seg;
 return seg.to_vector();
}

LEDA_END_NAMESPACE 
 
 
 
 
