
#include <cassert>
using namespace std;

#include <point.h>

#include <ruler.h>

#define PI 3.14159265359

void ruler::addAngleRuler
(
  doublec radius,
  doublec angle0,
  doublec angle1,
  doublec ticklenmajor,
  doublec ticklenmiddle,
  doublec ticklenminor
)
{
  assert(angle0 >= 0.0);
  assert(angle0 < angle1);

  gobjContainer * c = new gobjContainer();

  c->push( new gobjglBegin(GL_LINES) );

  doublec degtorad = PI / 180.0;
  double t;

  for (double s=angle0; s<=angle1; )
  {
    t = s * degtorad;
    //point2<double> const w(radius*cos(t),radus*sin(t));  //Save on trig calculations.
    point2<double> const nm(-cos(t),-sin(t));  // The normal
    point2<double> const w(-nm.x*radius,-nm.y*radius);  // Point on curve.

    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenmajor) ); 
    s += 10.0;
  }

  for (double s=angle0; s<=angle1; )
  {
    t = s * degtorad;
    point2<double> const nm(-cos(t),-sin(t));  // The normal
    point2<double> const w(-nm.x*radius,-nm.y*radius);  // Point on curve.

    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenmiddle) ); 
    s += 5.0;
  }

  for (double s=angle0; s<=angle1; )
  {
    t = s * degtorad;
    point2<double> const nm(-cos(t),-sin(t));  // The normal
    point2<double> const w(-nm.x*radius,-nm.y*radius);  // Point on curve.

    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenminor) ); 
    s += 1.0;
  }


  c->push(new gobjglEnd());

  push(c);
}


void ruler::addStraightRuler
(
  doublec len,
  point2<double> const & pos0,
  point2<double> const & pos1,
  doublec ticklenmajor,
  doublec ticklenmiddle,
  doublec ticklenminor
)
{
  uintc n = (uintc)(floor(len));

  //doublec dt = 1.0 / ((double)n - 1.0);
  doublec dt = 1.0 / len;

  point2<double> const p2(pos1-pos0);

  point2<double> tmp(-p2.y,p2.x);
  tmp.normalize();
  point2<double> const nm(tmp);

  gobjContainer * c = new gobjContainer();

  c->push( new gobjglBegin(GL_LINES) );

  for (uint i=0; i<n; ++i)
  {
    point2<double> w(pos0 + p2*(dt*i));

    // Write the major ticks.
    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenmajor) );

    // Write the middle ticks.
    point2<double> w2(pos0 + p2*(dt*(i+0.5)));
    c->push( new gobjglVertex2f(w2) );
    c->push( new gobjglVertex2f(w2 + nm * ticklenmiddle) );

    // Write the minor ticks
    for (uint k=1; k<=4; ++k)
    {
      point2<double> w3(pos0 + p2*(dt*(i+k*0.1)));
      c->push( new gobjglVertex2f(w3) );
      c->push( new gobjglVertex2f(w3 + nm * ticklenminor) );
    }
    for (uint k=1; k<=4; ++k)
    {
      point2<double> w3(pos0 + p2*(dt*(i+0.5+k*0.1)));
      c->push( new gobjglVertex2f(w3) );
      c->push( new gobjglVertex2f(w3 + nm * ticklenminor) );
    }
  }

  // Write the last major tick.
  if (len>1.0)
  {
    point2<double> w(pos0 + p2*(dt*n));
    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenmajor) );
  }

  // Write the last middle tick
  if ((len-n)>=0.5)
  {
    point2<double> w(pos0 + p2*(dt*(n+0.5)));
    c->push( new gobjglVertex2f(w) );
    c->push( new gobjglVertex2f(w + nm * ticklenmiddle) );
  }

  // The following suggests an easier way of writing this routine.
  // Instead of separating into cases, just write all the minor ticks
  // at once, then the middle and major ticks, overwriting the previous ones.
  // While it writes unnecessary lines its logic and code is much less.

  if ((len-n)>0.0)
  {
    for (double s=0.0, s1=len-n; s<=s1; )
    {
      point2<double> w(pos0 + p2*(dt*(n+s)));
      c->push( new gobjglVertex2f(w) );
      c->push( new gobjglVertex2f(w + nm * ticklenminor) ); 
      s += 0.1;
    }
  }

  c->push(new gobjglEnd());

  push(c);
}






