class Coord2
{
public:
  // Constructor
  //  x, y are coordinates
  //  v = 0 if this is a vector, 1 if it is a point
  Coord2( GLdouble x = 0, GLdouble y = 0, GLint v = 0 )
  {
    _x = x;
    _y = y;
    _v = v;
  }

  GLdouble x() const { return _x; }
  GLdouble y() const { return _y; }
  bool isVector() const { return _v == 0; }
  bool isPoint() const {return _v == 1; }
  void glVertex() const { glVertex2f( _x, _y ); }

private:
  GLdouble _x;     // x coordinate
  GLdouble _y;     // y coordinate
  GLint    _v;     // 0 if vector, 1 if point
    
};

// Build a Coord2 that is a vector
inline Coord Vec2( GLdouble x, GLdouble y) { return Coord2(x, y, 0); }

// Build a Coord2 that is a point
inline Coord Pt2( GLdouble x, GLdouble y) { return Coord2(x, y, 1); }

// Nothing below this point depends on the internal structure of the class

// Equality
inline bool operator == ( Coord2 c1, Coord2 c2 )
{
  return ( c1.x() == c2.x() && c1.y() == c2.y() && 
           ( c1.isVector() && c2.isVector() 
             || c1.isPoint() && c2.isPoint() ) );
}

// Inequality
inline bool operator != ( Coord2 c1, Coord2 c2 )
{
  return !(c1 == c2);
}

// c1 + c2 
//  Preconditions: either c1 or c2 is a vector
inline Coord2 operator + ( Coord2 c1, Coord2 c2 )
{
  assert( !(c1.isPoint() && c2.isPoint()) );
  if ( c1.isVector() && c2.isVector() )
    // sum of vectors is vector
    return( Vec2( c1.x()+c2.x(), c1.y()+c2.y() ) );
  else
    // sum of point and vector is point
    return( Pt2( c1.x()+c2.x(), c1.y()+c2.y() ) );
}

// c1 - c2
//  Precondition: Either c1 is not a vector or c2 is not a point
inline Coord2 operator - ( Coord2 c1, Coord2 c2 )
{
  assert( !( c1.isVector() &&  c2.isPoint() ) );
  if ( c1.isPoint() && c2.isVector() )
    // point - vector is point
    return( Pt2( c1.x()-c2.x(), c1.y()-c2.y() ) );
  else
    // point - point & vector - vector are both vector
    return( Vec2( c1.x()-c2.x(), c1.y()-c2.y() ) );
}

// s*c
//  Precondition: c is a vector
inline Coord2 operator * ( GLdouble scale, Coord2 c )
{
  assert( c.isVector() );
  return Vec2( c.x()*scale, c.y()*scale );
}

// c*s
//  Precondition: c is a vector
inline Coord2 operator * ( Coord2 c, GLdouble scale )
{
  assert( c.isVector() );
  return Vec2( c.x()*scale, c.y()*scale );
}

// c/s
//  Precondition: c is a vector
inline Coord2 operator / ( Coord2 c, GLdouble scale )
{
  assert( c.isVector() );
  return Vec2( c.x()/scale, c.y()/scale );
}


// lerp( c1, c2, GLdouble t )  
//  Precondition: c1 and c2 are of same type
// You were not required to provide this one, but it is now the only way
//   to get affine combinations of points
//   (Technically if c1 and c2 are points then t should be GLclampf, 
//    but this way we support extrapolation as well as interpolation.
//    Note that by the result is still well-formed because we use Pt2 or Vec2
//    to form it.)
inline Coord2 lerp( Coord2 c1, Coord2 c2, GLdouble t )
{
  assert( c1.isVector() && c2.isVector() || c1.isPoint() && c2.isPoint() );
  // By using "parametric" form operation is independent of type of args.
  return c1+t*(c2-c1);
}

// dot( c1, c2 ) --- dot product
//  Precondition: c1 and c2 are vectors
inline GLdouble dot( Coord2 c1, Coord2 c2 )
{
  assert( c1.isVector() && c2.isVector() );
  return ( c1.x()*c2.x() + c1.y()*c2.y() );
}

// norm( c ) --- magnitude of vector
//  Precondition: c is vector
inline GLdouble norm( Coord2 c )
{
  assert( c.isVector() );
  return sqrt( dot(c, c) );
}

// dist( c1, c2 ) --- Euclidean distance between points
//  Precondition: c1 and c2 are points
inline GLdouble dist( Coord2 c1, Coord2 c2 )
{
  assert( c1.isPoint() && c2.isPoint() );
  return norm(c1-c2);
}

// dir( c ) --- normalized direction vector of c
//  Precondition: c is vector
inline Coord2 dir( Coord2 c )
{
  assert( c.isVector() );
  return c/norm(c);
}

// perp( c ) --- CCW perpendicular of c
//  Precondition: c is vector
inline Coord2 perp( Coord2 c )
{
  assert( c.isVector() );
  return Vec2( -c.y(), c.x() );
}

// perpdot( c1, c2 ) --- dot of perp of c1 and c2
//  Precondition: c1 and c2 are vectors
inline GLdouble perpdot( Coord2 c1, Coord2 c2)
{
  assert( c1.isVector() && c2.isVector() );
  return dot( perp(c1), c2 );
}

