#include "pline.h"

#include <ads/ListIter.h>

#include <math.h>


pline::pline( struct resbuf *_rb ) : ADS_ENT_OBJ( _rb )
{
   assert(rb != NULL);
   struct resbuf *temp_rb = rb;

   while( temp_rb != NULL )
    {
      if (temp_rb->restype < 0) // possible -1 of -2

        {
          name[0] = temp_rb->resval.rlname[0];
          name[1] = temp_rb->resval.rlname[1];
        }
      else if (temp_rb->restype == 5)
        {
          _handle = temp_rb->resval.rstring;
        }
      temp_rb = temp_rb->rbnext;
    }
}

void pline::get_points()
{
   ads_name ent, result;

   ent[0] = name[0];
   ent[1] = name[1];

   char seqend = 0;

   while(ads_entnext(ent, result) == RTNORM && seqend == 0)
    {
      struct resbuf *temp_rb, *point_rb;

      point_rb = temp_rb = ads_entget(result);
      assert(temp_rb != NULL);

      while (point_rb != NULL)
        {
          if (point_rb->restype  == 10 )
            {
              vec3 point(point_rb->resval.rpoint[X], 
                         point_rb->resval.rpoint[Y],
                         point_rb->resval.rpoint[Z]);
              vertices.append(point);
              break;
            }
           else if (point_rb->restype == -2)
            {
              seqend++;
              break;
            }
          point_rb = point_rb->rbnext;
        }

      ads_relrb(temp_rb);
      ent[0] = result[0];
      ent[1] = result[1];
    }
}


double pline::nearest(const vec3 &p)
{
  if (vertices.isEmpty())
    get_points();

  ListIterators<vec3> iterator(vertices);

  iterator.reset();
  vec3 n, r0, r1 = *(iterator.currentItem());
  double t, temp_d, d = (p - r1).length2();

  for (iterator.next(); !iterator.isDone(); iterator.next() )
    {
      r0 = r1;
      r1 = *(iterator.currentItem());
      n = r1 - r0;
      t = (p - r0)*n/(n*n);
      if ( t > 1.0)
        temp_d = (p - r1).length2();
      else if ( t < 0.0)
        temp_d = (p - r0).length2();
      else
        temp_d = (p - (r0 + t*n)).length2();
//      ads_printf("temp_d = %lf\n", sqrt(temp_d));


      if (temp_d < d)
        d = temp_d;
    }

  return sqrt(d);
}


vec3
pline::first()
{
  if (vertices.isEmpty())
    get_points();
 
    ListIterators<vec3> iterator(vertices);

  iterator.reset();
  return *(iterator.currentItem());
}


vec3
pline::last()
{
  if (vertices.isEmpty())
    get_points();
  
  ListIterators<vec3> iterator(vertices);
  vec3 last;

  iterator.reset();
  for (iterator.next(); !iterator.isDone(); iterator.next() )
    {
      last =  *(iterator.currentItem());
    }
  return last;
}



void pline::Mark(const char * text, const char *layer, ads_real height)
{
  if (vertices.isEmpty())
    get_points();


  ListIterators<vec3> iterator(vertices);
  vec3 from, to, middle, dir;

  int total = 0;
  for (iterator.reset(); !iterator.isDone(); iterator.next() )
      total++;

  int count = 0;
  for (iterator.reset() ; (count < (total/2 - 1 )); iterator.next() )
      count++;
  from =  *(iterator.currentItem());
  iterator.next();
  to =  *(iterator.currentItem());

  dir = to  - from;
  middle = from + 0.5 *  dir;

  ads_point point = {middle[0], middle[1], middle[2]};


  dir.normalize();

  ads_real rotation =  dir[VY] < 0 ?  6.28318530718 - acos(dir[VX])
              : acos(dir[VX]);

  struct resbuf *rb = ads_buildlist (RTDXF0, "TEXT", 
                                     8, layer, // layer

                                     10, point,   // insertion point

                                     1, text,
                                     40, height,
                                     50, rotation,
                                     62, 2, // color blue

                                     0);
  assert(rb != NULL);
  int status = ads_entmake(rb);

  assert(status == RTNORM);

  ads_relrb(rb);
}



syntax highlighted by Code2HTML, v. 0.9.1