// $Source: /local/data/cvs/yellowbank/tile/qedge.cc,v $
// $Revision: 1.3 $
// $State: Exp $
// $Date: 2004/07/19 03:54:07 $
// $Author: yrp001 $
// $Locker:  $

#include <iostream>
#include "qedge.h"

qedge::
qedge()
  : _p1(), _p2(), _angle()
{}

qedge::
qedge( const qpoint& a, const qpoint& b )
  : _p1( a ), _p2( b )
{
  qpoint pt = _p2 - _p1;
  _angle = pt.angle();
}

qedge::
qedge( const qpoint& point, double angle )
  : _p1( point )
{
  _p2.setx( cos( angle ) + point.getx() );
  _p2.sety( sin( angle ) + point.gety() );
}

// from usenet graphics FAQ
// see also GemsIII: fast line intersection
// 
// Working
//
qpoint
qedge::
intersect( const qedge& other, int* i, double* r, double* s ) const {

  // use same notation as FAQ
  double ax, ay, bx, by, cx, cy, dx, dy;

  ax = _p1.getx();
  ay = _p1.gety();
  bx = _p2.getx();
  by = _p2.gety();
  cx = other._p1.getx();
  cy = other._p1.gety();
  dx = other._p2.getx();
  dy = other._p2.gety();

  double denom, numr;

  denom = ((bx - ax) * (dy - cy)) - ((by - ay) * (dx - cx));
  numr = ((ay - cy) * (dx - cx)) - ((ax - cx) * (dy - cy));
  if( denom == 0.0 ) {
    if( numr == 0.0 )
      *i = 0;
    else
      *i = 1;
    return qpoint( 0.0, 0.0 );
  }

  *i = 2;
  *r = numr / denom;
  *s = (((ay - cy) * (bx - ax)) - ((ax - cx) * (by - ay))) / denom;

  double px, py;
  px = ax + ((*r) * (bx - ax));
  py = ay + ((*r) * (by - ay));
  return qpoint( px, py );
}

int
qedge::
side( const qpoint& p ) const {
  qpoint pt = p - _p1;
  qangle at = pt.angle();

  float ll = _angle.valrad();
  float ul = ll + M_PI;
  if( ul > Q_2_PI ) {
    ll = ul - Q_2_PI;
    ul = _angle.valrad();
  }

  float atv = at.valrad();
  if( atv > ll && atv < ul )
    return -1;
  return 1;
  //  else if( atv < M_PI && atv > 0 )
  //    return -1;
  //  return 0;
}

qangle
qedge::
angle() const {
  qpoint p = _p2 - _p1;
  return p.angle();
}

float
qedge::
anglef() const {
  qpoint p = _p2 - _p1;
  return p.anglef();
}

float
qedge::
projection( const qpoint& point, qpoint* ppoint ) const {
  float ax, ay, bx, by, cx, cy;
  float l, r;
  float px, py;

  qpoint p = _p2 - _p1;
  l = p.length();

  ax = _p1.getx();
  ay = _p1.gety();
  bx = _p2.getx();
  by = _p2.gety();
  cx = point.getx();
  cy = point.gety();
  
  r = (((cx - ax) * (bx - ax)) + ((cy - ay) * (by - ay))) / (l * l);

  px = ax + (r * (bx - ax));
  py = ay + (r * (by - ay));

  ppoint->setx( px );
  ppoint->sety( py );
  return r;
}

float
qedge::
distance( const qpoint& point ) const {
  qpoint p;
  projection( point, &p );
  p = p - point;
  if( side( point ) == -1 )
    return p.length() * -1;
  return p.length();
}

std::ostream&
operator<<( std::ostream& os, qedge& e ) {
  return os << e._p1 << " " << e._p2;
}

std::istream&
operator>>( std::istream& is, qedge& e ) {
  is >> e._p1;
  is >> e._p2;
  return is;
}

