#ifndef POLARLINE_H
#define POLARLINE_H

#include "opencvext.h"
#include <iostream>
#include <iomanip>

namespace seemicro
{

extern int DEBUGLEVEL;

/**
  * Eine Grade in Polarkoordinatendarstellung
  *
  * angles are in radians, ie. 0 <= theta < 2*M_PI
  * angle of 0 points into positive x axis direction, ie. right
  * angle of M_PI/2 results in positive y axis
  *   [direction depends on display method...]
  * centers of imgs are taken as 0 of polar coordinate system
  */
struct polarLine
{
  /**
    * r == Abstand zwischen dem Punkt der Gerade, der dem
    * Koordinatenursprung am nächsten kommt, zum
    * Koordinatenursprung
    *
    * theta == Winkel der Geraden relativ zur positiven x-Achse
    */
  double r, theta;
  polarLine() {}
  polarLine(double r1, double t1) { r = r1; theta = t1; }

  /**
    * stellt sicher, daß r>=0
    */
  void normalize()
  {
     if(r<0)
    {
      r=fabs(r);
      theta += M_PI;
      if(theta>=2*M_PI) theta-=2*M_PI;
    }
  }

  /**
    * Converts line given in cartesian coordiantes
    * and where positive y-axis points downwards
    * of an image with dimensions w, h
    * into a line in the polar coordinate system
    * centered at w/2 h/2
    * where positive y-axis points upwards
    */
  void fromCart(int w, int h, CvPoint p1, CvPoint p2)
  {
    // for a single point I:
    // M(I)=sqrt( X(I)^2+Y(I)^2 ),
    // A(I)=atan( Y(I)/X(I) )

    // aus computergraphischem kartesischem koordinatensys.
    // int math. Koordinatensys. mit Nullpunkt in Bildmitte
    // umrechnen
    p1.x -= w/2;
    p2.x -= w/2;
    p1.y -= h/2;
    p2.y -= h/2;

    // an x-Achse spiegeln
    p1.y = -p1.y;
    p2.y = -p2.y;

    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;

    theta = atan2(dy, dx);
//    std::cerr << "atan2: " << std::fixed << std::setprecision(1) <<
//      theta*180./M_PI << "° ("<<theta<<")\n";
//    theta = atan(dy/dx);
//    theta += M_PI/2;

    if(theta<-M_PI/2)
    {
      theta = 3*M_PI/2+theta;
    }
    else if(theta<0)
    {
      theta = 3*M_PI/2+theta;
    }
    else if(theta>M_PI/2)
    {
      theta = theta-M_PI/2;
    }
    else
      theta = theta+M_PI/2;

    double theta1 = atan2(double(p1.y), double(p1.x));
//    double theta1 = atan(double(p1.y)/double(p1.x));
    double r1 = sqrt(sqr(p1.x)+sqr(p1.y));
//    r = sin(theta-theta1)*r1;
    r = cos(theta-theta1)*r1;
//    std::cerr << std::fixed << std::setprecision(1) << "dx:" << dx << " dy:" << dy
//      << " theta:" << theta << " theta1:" << theta1
//      << " r1:" << r1 << " r:" << r << std::endl;

    normalize();
    assert(r>=0);
    assert(theta>=0);
    assert(theta<=2*M_PI);
  }

 void draw(IplImage *img, double color=255);

/**
  * Findet Schnittpunkte p1, p2 des Kreises gegeben durch radius
  * (Mittelpunkt == (0, 0)) mit der Geraden geg. durch r, theta in
  * Polardarstellung.
  * Liefert -1 if keine Schnittpunkte, else 0.
  */
int find_p1_p2(mypoint& p1, mypoint& p2, float radius)
{
  // lösen einer quadratischen Gleichung (in Normalform)
  float p = -2*r*sin(theta);
  float q = r*r-radius*radius*cos(theta)*cos(theta);
  float det = p*p/4 - q;

  if(det<0)
  {
    p1.p.x = p1.p.y = p2.p.x = p2.p.y = 0;
#if defined(DEBUG) || defined(_DEBUG)
    if(DEBUGLEVEL>=1)
      std::cerr << "find_p1_p2(): det = " << det << " < 0\n";
#endif
    return -1;
  }

  float y1 = -p/2 + sqrt(det);
  float y2 = -p/2 - sqrt(det);

  // numerisch instabil, wenn cos(theta) ~= 0,
  // da r/cos(theta) -> +-INF
  // und yx*tan(theta) -> +-INF
  float rct = 0;
  float ct=cos(theta);
  if(fabs(ct) > 1e-6)
  {
    rct = r/ct;
    //  anders: x = (r-y*sin(theta)) / cos(theta);
    p1.p.x = int((rct-y1*tan(theta)));
    p2.p.x = int((rct-y2*tan(theta)));
  }
  else
  { // y1~r -> 0 // y1~0 -> r
    // geht folgendes kürzer? try mupad!
    p1.p.x = int( radius*cos(asin(r/radius)) );
    p2.p.x = -p1.p.x;
//    if(DEBUGLEVEL>=1)
  //    std::cerr << "find_p1_p2(): p1="<<p1<<std::endl;
  }

  p1.p.y = -int(y1);
  p2.p.y = -int(y2);
  return 0;
}

}; // polarLine

std::ostream& operator<<(std::ostream& s, const polarLine& l);

} // namespace seemicro

#endif

