/**
 * ============================================================================
 *                   Software License
 * ============================================================================
 *
 *    Copyright (C) 2001 Johannes Zemlin. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modifica-
 * tion, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The end-user documentation included with the redistribution, if any, must
 *    include the following  acknowledgment: "This product includes software
 *    developed by Johannes Zemlin (http://zemlin-online.de/)."
 *    Alternately, this acknowledgment may appear in the software itself, if
 *    and wherever such third-party acknowledgments normally appear.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE  DISCLAIMED. IN NO  EVENT SHALL
 * JOHANNES ZEMLIN OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
 * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR  PROFITS; OR BUSINESS INTERRUPTION)  HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER  IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package zemlin.fritz;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

/**
 *@author     <A href=mailto:Johannes@zemlin-online.de>Johannes Zemin</A>
 *@created    20. August 2001
 */
public class TableauCanvas extends Canvas {

    // Defokussierung (Stärke)
    private double delta = 2.7;

    // Astigmatismus (Stärke)
    private double deltaA = 0.23;

    // Astigmatismus (Richtung)
    private double fiA = -88 * Math.PI / 180;

    // Kippung (Stärke)
    private double R0 = 1.1;

    // Koma (Stärke)
    private double B = 0.68;

    // Koma (Richtung)
    private double fiB = -75 * Math.PI / 180;

    // dreizähliger Astigmatismus (Stärke)
    private double A3 = 0.06;

    // dreizähliger Astigmatismus (Richtung)
    private double fiA3 = 13 * Math.PI / 180;


    /**
     *  Constructor for the TableauCanvas object
     */
    public TableauCanvas() {
    }


    /**
     *  Sets the Delta attribute of the TableauCanvas object
     *
     *@param  v  The new Delta value
     */
    public void setDelta(double v) {
        delta = v;
    }


    /**
     *  Sets the DeltaA attribute of the TableauCanvas object
     *
     *@param  v  The new DeltaA value
     */
    public void setDeltaA(double v) {
        deltaA = v;
    }


    /**
     *  Sets the FiA attribute of the TableauCanvas object
     *
     *@param  v  The new FiA value
     */
    public void setFiA(double v) {
        fiA = v;
    }


    /**
     *  Sets the R0 attribute of the TableauCanvas object
     *
     *@param  v  The new R0 value
     */
    public void setR0(double v) {
        R0 = v;
    }


    /**
     *  Sets the B attribute of the TableauCanvas object
     *
     *@param  v  The new B value
     */
    public void setB(double v) {
        B = v;
    }


    /**
     *  Sets the FiB attribute of the TableauCanvas object
     *
     *@param  v  The new FiB value
     */
    public void setFiB(double v) {
        fiB = v;
    }


    /**
     *  Sets the A3 attribute of the TableauCanvas object
     *
     *@param  v  The new A3 value
     */
    public void setA3(double v) {
        A3 = v;
    }


    /**
     *  Sets the FiA3 attribute of the TableauCanvas object
     *
     *@param  v  The new FiA3 value
     */
    public void setFiA3(double v) {
        fiA3 = v;
    }


    /**
     *  Description of the Method
     *
     *@param  g  Description of Parameter
     */
    public void paint(Graphics g) {
        // Größe der Zeichenfläche
        Dimension s = getSize();

        // Koordinatensystem
        g.drawLine(0, s.height / 2, s.width, s.height / 2);
        g.drawLine(s.width / 2, 0, s.width / 2, s.height);

        // Mittelpunkt
        int zeroX = s.width / 2;
        int zeroY = s.height / 2;

        double k = Math.PI / 6;
        //double k = Math.PI / 10;
        double fiR0 = 0;
        long start = System.currentTimeMillis();

        double offset = Math.min(s.height, s.width) / 2.5;
        while (fiR0 < 2 * Math.PI) {
            g.translate(
                    (int) (zeroX + Math.sin(fiR0) * offset),
                    (int) (zeroY + Math.cos(fiR0) * offset));
            paintLiniensystem(g, s, 1, delta, deltaA, fiA, R0, fiR0, B, fiB, A3, fiA3);
            g.translate(
                    -(int) (zeroX + Math.sin(fiR0) * offset),
                    -(int) (zeroY + Math.cos(fiR0) * offset));
            fiR0 += k;
        }
        g.translate(zeroX, zeroY);
        paintLiniensystem(g, s, 1, delta, deltaA, fiA, 0, 0, B, fiB, A3, fiA3);

        System.out.println("time to calc tableau: " + (System.currentTimeMillis() - start));
    }


    /**
     *  Description of the Method
     *
     *@param  g       Description of Parameter
     *@param  s       Description of Parameter
     *@param  s1      Description of Parameter
     *@param  delta   Description of Parameter
     *@param  deltaA  Description of Parameter
     *@param  fiA     Description of Parameter
     *@param  R0      Description of Parameter
     *@param  fiR0    Description of Parameter
     *@param  B       Description of Parameter
     *@param  fiB     Description of Parameter
     *@param  A3      Description of Parameter
     *@param  fiA3    Description of Parameter
     */
    private void paintLiniensystem(
            Graphics g,
            Dimension s,
            int s1,
            double delta,
            double deltaA,
            double fiA,
            double R0,
            double fiR0,
            double B,
            double fiB,
            double A3,
            double fiA3) {

        int rangeLeft = -6;
        int rangeRight = 6;
        for (int n = rangeLeft; n <= rangeRight; n++) {
            paintKnotenlinie(g, s, 1, delta, deltaA, fiA, R0, fiR0, B, fiB, A3, fiA3, n);
        }
    }


    /**
     *  Description of the Method
     *
     *@param  g       Description of Parameter
     *@param  s       Description of Parameter
     *@param  s1      Description of Parameter
     *@param  delta   Description of Parameter
     *@param  deltaA  Description of Parameter
     *@param  fiA     Description of Parameter
     *@param  R0      Description of Parameter
     *@param  fiR0    Description of Parameter
     *@param  B       Description of Parameter
     *@param  fiB     Description of Parameter
     *@param  A3      Description of Parameter
     *@param  fiA3    Description of Parameter
     *@param  n       Description of Parameter
     */
    private void paintKnotenlinie(
            Graphics g,
            Dimension s,
    //double fi,
            int s1,
    //int s2,
            double delta,
            double deltaA,
            double fiA,
            double R0,
            double fiR0,
            double B,
            double fiB,
            double A3,
            double fiA3,
            int n) {

        double scaleFi = 0.07 * Math.min(s.height, s.width) / 2;
        //double scaleFi = 0.05 * Math.min(s.height, s.width) / 2;
        double d = Math.PI * 0.005;
        double fi = 0;
        double r;
        int x;
        int y;
		g.setColor(Color.black);
        while (fi < 2 * Math.PI) {
            r = radius(fi, s1, 1, delta, deltaA, fiA, R0, fiR0, B, fiB, A3, fiA3, n);
//			System.out.println(r + " " + fi);
            x = (int) Math.round(Math.sin(fi) * r * scaleFi);
            y = (int) Math.round(Math.cos(fi) * r * scaleFi);
            
            g.drawLine(x, y, x, y);

            r = radius(fi, s1, -1, delta, deltaA, fiA, R0, fiR0, B, fiB, A3, fiA3, n);
            x = (int) Math.round(Math.sin(fi) * r * scaleFi);
            y = (int) Math.round(Math.cos(fi) * r * scaleFi);
            g.drawLine(x, y, x, y);

            fi += d;
        }
    }


    /**
     *  Ermittelt den Radius
     *
     *@param  fi      Azimut (0 - 2 * pi)
     *@param  s1      Faktor +1/-1
     *@param  s2      Faktor +1/-1
     *@param  delta   Defokusierung
     *@param  deltaA  Astigmatismus (Stärke)
     *@param  fiA     Astigmatismus (Richtung)
     *@param  R0      Kippung (Stärke)
     *@param  fiR0    Kippung (Richtung)
     *@param  B       Koma (Stärke)
     *@param  fiB     Koma (Richtung)
     *@param  n       Kurvenparameter / Nullstellen
     *@param  A3      Description of Parameter
     *@param  fiA3    Description of Parameter
     *@return         Description of the Returned Value
     */
    private double radius(
            double fi,
            int s1,
            int s2,
            double delta,
            double deltaA,
            double fiA,
            double R0,
            double fiR0,
            double B,
            double fiB,
            double A3,
            double fiA3,
            int n) {

        double op1 = op1(fi, delta, deltaA, fiA, R0, fiR0, B, fiB, A3, fiA3);
		//System.out.println(op1);
        double op2 = Math.pow(op1, 2);
        double op3 = 2 * n;

        double op4 = op2 + s1 * op3;

        if (op4 < 0) {
        	
            return Double.NaN;
        }

        double op5 = Math.sqrt(op4);

        double op6 = -1 * op1 + s2 * op5;

        if (op6 < 0) {
            return Double.NaN;
        }
        return Math.sqrt(op6);
    }


    /**
     *  Ermittelt den Radius
     *
     *@param  fi      Azimut (0 - 2*pi)
     *@param  delta   Defokusierung
     *@param  deltaA  Astigmatismus (Stärke)
     *@param  fiA     Astigmatismus (Richtung)
     *@param  R0      Kippung (Stärke)
     *@param  fiR0    Kippung (Richtung)
     *@param  B       Koma (Stärke)
     *@param  fiB     Koma (Richtung)
     *@param  A3      Description of Parameter
     *@param  fiA3    Description of Parameter
     *@return         Description of the Returned Value
     */
    private double op1(
            double fi,
            double delta,
            double deltaA,
            double fiA,
            double R0,
            double fiR0,
            double B,
            double fiB,
            double A3,
            double fiA3) {
            	
		double sum1 = -1 * delta + 2 * R0 * R0 + 4 * B * R0 * Math.cos(fiB - fiR0);
		if (sum1 == Double.NaN) {
		}
        //
        //
        return -1 * delta + 2 * R0 * R0 + 4 * B * R0 * Math.cos(fiB - fiR0) -
                deltaA * Math.cos(2 * fiA - 2 * fi) +
                R0 * R0 * Math.cos(2 * fiR0 - 2 * fi) +
                2 * B * R0 * Math.cos(fiB + fiR0 - 2 * fi) +
                6 * A3 * R0 * Math.cos(3 * fiA3 - fiR0 - 2 * fi);
    }

}

