module FD {
    export class PolarPoint2D {

        public PI = Math.PI;
        public PI_05 = Math.PI * 0.5;
        public PI_075 = Math.PI * 0.75;
        public PI_10 = Math.PI;
        public PI_15 = Math.PI * 1.5;
        public PI_20 = Math.PI * 2.0;
        public PI_25 = Math.PI * 2.5;

        length_ : number;
        angle_ : number;

        constructor(length:number=0,angle:number=0) {
           this.length_=length;
           this.angle_=angle; 
        }
    
        public clear(){
            this.angle_=0;
            this.length_=0;
        }

        public set(length:number, angle:number)
        {
            this.length_ = length;
            this.angle_ = this.normalizeAngle (angle);
        }

        public setCartesian(posx:number, posy:number)
        {
            this.angle_ = this.getPolarAngle (posx, posy);
            this.length_ = this.getPolarLength (posx, posy);
        }

        public getLength (){
            return this.length_;
        }

        public getAngle (){
            return this.angle_;
        }


        public getPosX (){
            return this.length_ * Math.cos (this.angle_);
        }


        public getPosY (){
            return this.length_ * Math.sin (this.angle_);
        }


        public addAngle (angle:number){
            this.angle_ = this.normalizeAngle(this.angle_ + angle);
        }

        public distanceAngle (angle2:number){
            return this.polarDistanceAngle (this.angle_, angle2);
        }


        public copy (sourcepoint:PolarPoint2D){
            this.length_ = sourcepoint.getLength ();
            this.angle_ = sourcepoint.getAngle ();
        }

        public normalizeAngle (angle:number){
            // fist check (needs no calculation time)
            if (angle < this.PI_20 && angle >= 0)
              return angle;

            // second check (needs less calculation time)
            if (angle < 0 && angle >= this.PI_20*-1)
              return angle + this.PI_20;

            // full calculation for all cases
            angle = angle % this.PI_20;
            if (angle < 0)
              angle += this.PI_20;

            return angle;
        }

        public  polarDistanceAngle(angle1:number, angle2:number){
            // normalize angles
            angle1 = this.normalizeAngle (angle1);
            angle2 = this.normalizeAngle (angle2);

            // calculate distance
            var distance = angle2 - angle1;

            // find the smaller one
            if (distance > this.PI)
              distance -= this.PI_20;
            else if (distance < -this.PI)
              distance += this.PI_20;

            return distance;
        }

        public getPolarAngle(posx:number, posy:number){
            // return zero, if y =0 and x equal or greater 0
            // the tan2 returns
            if (posy == 0 && posx >= 0)
              return 0;

            var tanangle = Math.atan2 (posx, posy);
            //System.err.println ("\ntanangle: " + tanangle + " / " + round2 (toDegrees (tanangle)));

            var angle;

            // calculate real angle in circle from atan2-value
            if (tanangle < 0)  
            {
              // the left hemisphere
              angle = -tanangle + this.PI_05;
            }
            else // if (tanangle > 0d) 
            {
              // the right hemisphere
              if (tanangle < this.PI_05) 
              {
                // the top right quarter
                angle = this.PI_05 - tanangle;
              }
              else
              {
                // the bottom right quarter
                angle = this.PI_25 - tanangle;
              }
            }

            return angle;
        }

        public getPolarLength(posx:number, posy:number){
            return Math.sqrt (posx * posx + posy * posy);
        }
    }
}
