text: #include <math.h>
  #include "qwt3d_color.h"
  #include "qwt3d_plot.h"
  #include "qwt3d_enrichment_std.h"
  
  using namespace Qwt3D;
  
  
  /////////////////////////////////////////////////////////////////
  //
  //   CrossHair
  //
  /////////////////////////////////////////////////////////////////
  
  CrossHair::CrossHair()
  {
    configure(0, 1, false, false);
  }
  
  CrossHair::CrossHair(double rad, double linewidth, bool smooth, bool boxed)
  {
    configure(rad, linewidth, smooth, boxed);
  }
  
  void CrossHair::configure(double rad, double linewidth, bool smooth, bool boxed)
  {
    plot = 0;
    radius_ = rad;
    linewidth_ = linewidth;
    smooth_ = smooth;
    boxed_ = boxed;
  }
  
  void CrossHair::drawBegin()
  {
    setDeviceLineWidth( linewidth_ );
    oldstate_ = glIsEnabled(GL_LINE_SMOOTH);
    if (smooth_)
      glEnable(GL_LINE_SMOOTH);
    else
      glDisable(GL_LINE_SMOOTH);
  	glBegin( GL_LINES );
  }
  
  void CrossHair::drawEnd()
  {
    glEnd();
  
    if (oldstate_)
      glEnable(GL_LINE_SMOOTH);
    else
      glDisable(GL_LINE_SMOOTH);
  }
  
  void CrossHair::draw(Qwt3D::Triple const& pos)
  {
  	RGBA rgba = (*plot->dataColor())(pos);
  	glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
  
    double diag = (plot->hull().maxVertex-plot->hull().minVertex).length() * radius_;
  
    glVertex3d( pos.x - diag, pos.y, pos.z); 
  	glVertex3d( pos.x + diag, pos.y, pos.z); 
  	
    glVertex3d( pos.x, pos.y - diag, pos.z); 
  	glVertex3d( pos.x, pos.y + diag, pos.z); 
    
    glVertex3d( pos.x, pos.y, pos.z - diag); 
  	glVertex3d( pos.x, pos.y, pos.z + diag); 
  
    // hull
    
    if (!boxed_)
      return;
  
    glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
  	glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
    glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
  	glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
    
    glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
  	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
    glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
  	glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
  
    glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
  	glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
    glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
  	glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
    
    glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
  	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
    glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
  	glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
  
    glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag); 
  	glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag); 
    glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag); 
  	glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag); 
    
    glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag); 
  	glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag); 
    glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag); 
  	glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag); 
  }
  
  /////////////////////////////////////////////////////////////////
  //
  //   Dot
  //
  /////////////////////////////////////////////////////////////////
  
  Dot::Dot()
  {
    configure(1, false);
  }
  
  Dot::Dot(double pointsize, bool smooth)
  {
    configure(pointsize, smooth);
  }
  
  void Dot::configure(double pointsize, bool smooth)
  {
    plot = 0;
    pointsize_ = pointsize;
    smooth_ = smooth;
  }
  
  void Dot::drawBegin()
  {
    setDevicePointSize( pointsize_ );
    oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
    if (smooth_)
      glEnable(GL_POINT_SMOOTH);
    else
      glDisable(GL_POINT_SMOOTH);
  
    //glPointSize(10);
  	glBegin( GL_POINTS );
  }
  
  void Dot::drawEnd()
  {
    glEnd();
  
    if (oldstate_)
      glEnable(GL_POINT_SMOOTH);
    else
      glDisable(GL_POINT_SMOOTH);
  }
  
  void Dot::draw(Qwt3D::Triple const& pos)
  {
  	RGBA rgba = (*plot->dataColor())(pos);
    glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
    glVertex3d( pos.x, pos.y, pos.z);   
  }
  
  
  /////////////////////////////////////////////////////////////////
  //
  //   Cone
  //
  /////////////////////////////////////////////////////////////////
  
  Cone::Cone()
  {
  	hat      = gluNewQuadric();
  	disk     = gluNewQuadric();
  
    configure(0, 3);
  }
  
  Cone::Cone(double rad, unsigned quality)
  {
  	hat      = gluNewQuadric();
  	disk     = gluNewQuadric();
  
    configure(rad, quality);
  }
  
  Cone::~Cone()
  {
  	gluDeleteQuadric(hat);
  	gluDeleteQuadric(disk);
  }
  
  void Cone::configure(double rad, unsigned quality)
  {
    plot = 0;
    radius_ = rad;
    quality_ = quality;
    oldstate_ = GL_FALSE;
  
  	gluQuadricDrawStyle(hat,GLU_FILL);
  	gluQuadricNormals(hat,GLU_SMOOTH);
  	gluQuadricOrientation(hat,GLU_OUTSIDE);
  	gluQuadricDrawStyle(disk,GLU_FILL);
  	gluQuadricNormals(disk,GLU_SMOOTH);
  	gluQuadricOrientation(disk,GLU_OUTSIDE);
  }
  
  void Cone::draw(Qwt3D::Triple const& pos)
  {  
  	RGBA rgba = (*plot->dataColor())(pos);
    glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
  
    GLint mode;
  	glGetIntegerv(GL_MATRIX_MODE, &mode);
  	glMatrixMode( GL_MODELVIEW );
    glPushMatrix();
  
    glTranslatef(pos.x, pos.y, pos.z);
  
    gluCylinder(hat, 0.0, radius_, radius_*2, quality_, 1);
    glTranslatef(0, 0, radius_*2);
  	gluDisk(disk, 0.0, radius_, quality_, 1);
  
    glPopMatrix();
  	glMatrixMode(mode);
  }
  
  
  /////////////////////////////////////////////////////////////////
  //
  //   Arrow
  //
  /////////////////////////////////////////////////////////////////
  
  Arrow::Arrow()
  {	
  	hat      = gluNewQuadric();
  	disk     = gluNewQuadric();
  	base    = gluNewQuadric();
  	bottom   = gluNewQuadric();
  
  	gluQuadricDrawStyle(hat,GLU_FILL);
  	gluQuadricNormals(hat,GLU_SMOOTH);
  	gluQuadricOrientation(hat,GLU_OUTSIDE);
  	gluQuadricDrawStyle(disk,GLU_FILL);
  	gluQuadricNormals(disk,GLU_SMOOTH);
  	gluQuadricOrientation(disk,GLU_OUTSIDE);
  	gluQuadricDrawStyle(base,GLU_FILL);
  	gluQuadricNormals(base,GLU_SMOOTH);
  	gluQuadricOrientation(base,GLU_OUTSIDE);
  	gluQuadricDrawStyle(bottom,GLU_FILL);
  	gluQuadricNormals(bottom,GLU_SMOOTH);
  	gluQuadricOrientation(bottom,GLU_OUTSIDE);
  
  	configure(3, 0.4, 0.06, 0.02);
  }
  
  Arrow::~Arrow()
  {
  	gluDeleteQuadric(hat);
  	gluDeleteQuadric(disk);
  	gluDeleteQuadric(base);
  	gluDeleteQuadric(bottom);
  }
  
  /**
  \param segs number of faces for the fields arrows (see the gallery for examples)
  \param relconelength see picture
  \param relconerad see picture
  \param relstemrad see picture
  \image html arrowanatomy.png 
  */
  void Arrow::configure(int segs, double relconelength, double relconerad, double relstemrad)
  {
  	plot = 0;
    segments_ = segs;
    oldstate_ = GL_FALSE;
  	rel_cone_length = relconelength;
  	rel_cone_radius = relconerad;
  	rel_stem_radius = relstemrad;	
  }
  
  void Arrow::draw(Qwt3D::Triple const& pos)
  {	
  	Triple end = top_;
  	Triple beg = pos;
  	Triple vdiff = end-beg;
  	double length = vdiff.length();
  	glColor4d(rgba_.r,rgba_.g,rgba_.b,rgba_.a);
  
  	double radius[2];
  	radius[0] = rel_cone_radius * length;
  	radius[1] = rel_stem_radius * length;
  	
  	GLint mode;
  	glGetIntegerv(GL_MATRIX_MODE, &mode);
  
  	glMatrixMode( GL_MODELVIEW );
    glPushMatrix();
  
  
  	Triple axis;
  	double phi = calcRotation(axis, FreeVector(beg,end));
  	
  	glTranslatef(beg.x, beg.y, beg.z);
    glRotatef(phi, axis.x, axis.y, axis.z);
  
  	double baseheight = (1-rel_cone_length) * length;
  	
  	glTranslatef(0, 0, baseheight);
  
  	gluCylinder(hat, radius[0], 0.0, rel_cone_length * length, segments_,1);
  	gluDisk(disk,radius[1],radius[0], segments_,1);
  	
  	glTranslatef(0, 0, -baseheight);
  	
  	gluCylinder(base, radius[1],radius[1], baseheight,segments_,1);
  	gluDisk(disk,0,radius[1],segments_,1);
  
    glPopMatrix();
  	glMatrixMode(mode);
  }
  
  
  //! transform a vector on the z axis with length |beg-end|, to get them in coincidence with the vector(beg,end)
  /**
  	\return Angle in degree to rotate
  	\param axis   The axis to rotate around
  	\param beg    result vector base point
  	\param end    result vector top point
  */ 
  double Arrow::calcRotation(Triple& axis, FreeVector const& vec)
  {
  	
  	Triple end = vec.top;
  	Triple beg = vec.base;
  
  	Triple firstbeg(0.0,0.0,0.0);
  	Triple firstend(0.0,0.0,(end-beg).length());
  	
  	Triple first = firstend - firstbeg;
  	first.normalize();
  
  	Triple second = end-beg;
  	second.normalize();
  
  	axis = normalizedcross(first,second);
  	double cosphi = dotProduct(first,second);
  	
  	return 180 * acos(cosphi) / Qwt3D::PI;
  }
  