/**
 * ============================================================================
 *                   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 AberrationCanvas 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;

    // 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 AberrationCanvas object
     *
     *@param  chimax  Description of Parameter
     */
    public AberrationCanvas(int chimax) {
    }


    /**
     *  Sets the Delta attribute of the AberrationCanvas object
     *
     *@param  v  The new Delta value
     */
    public void setDelta(double v) {
        delta = v;
    }


    /**
     *  Sets the DeltaA attribute of the AberrationCanvas object
     *
     *@param  v  The new DeltaA value
     */
    public void setDeltaA(double v) {
        deltaA = v;
    }


    /**
     *  Sets the FiA attribute of the AberrationCanvas object
     *
     *@param  v  The new FiA value
     */
    public void setFiA(double v) {
        fiA = v;
    }


    /**
     *  Sets the R0 attribute of the AberrationCanvas object
     *
     *@param  v  The new R0 value
     */
    public void setR0(double v) {
    }


    /**
     *  Sets the B attribute of the AberrationCanvas object
     *
     *@param  v  The new B value
     */
    public void setB(double v) {
        B = v;
    }


    /**
     *  Sets the FiB attribute of the AberrationCanvas object
     *
     *@param  v  The new FiB value
     */
    public void setFiB(double v) {
        fiB = v;
    }


    /**
     *  Sets the A3 attribute of the AberrationCanvas object
     *
     *@param  v  The new A3 value
     */
    public void setA3(double v) {
        A3 = v;
    }


    /**
     *  Sets the FiA3 attribute of the AberrationCanvas 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();

        // Mittelpunkt
        int zeroX = s.width / 2;
        int zeroY = s.height / 2;
        int rmax = Math.min(s.width, s.height) / 2;

        long start = System.currentTimeMillis();

        // 21.4.2001
        // scale abberation radius
        double scale = 0.5;

        System.out.println("0, 0 " + calcValue(0.001, 0.001));

        for (int x = -rmax; x < rmax; x++) {
            for (int y = -rmax; y < rmax; y++) {

                float r = (float) Math.sqrt(x * x + y * y) / rmax;
                if (r > 1) {
                    continue;
                }
                g.setColor(calcColor(calcValue((double) x / ((double) rmax * scale), (double) y / ((double) rmax * scale))));
                
                g.drawLine(zeroX + x, zeroY + y, zeroX + x, zeroY + y);
            }
        }

        g.setColor(Color.black);
        // Koordinatensystem
        g.drawLine(0, s.height / 2, s.width, s.height / 2);
        for (int i = -4; i <= 4; i++) {
            g.drawLine((int) (s.width / 2 + (i * (rmax / (8 * scale)))),
                    s.height / 2 - 2,
                    (int) (s.width / 2 + (i * (rmax / (8 * scale)))),
                    s.height / 2 + 2);
            if (i != 0) {
                g.drawString(String.valueOf(i / 2.0),
                        (int) (s.width / 2 + (i * (rmax / (8 * scale))) - 10),
                        s.height / 2 + 15);
            }
        }
        g.drawLine(s.width / 2, 0, s.width / 2, s.height);

        for (int i = -4; i <= 4; i++) {
            g.drawLine(s.width / 2 - 2,
                    (int) (s.height / 2 + (i * (rmax / (8 * scale)))),
                    s.width / 2 + 2,
                    (int) (s.height / 2 + (i * (rmax / (8 * scale)))));
            if (i != 0) {
                g.drawString(String.valueOf(i / 2.0),
                        s.width / 2 - 25,
                        (int) (s.height / 2 - (i * (rmax / (8 * scale)))) + 5);
            }
        }
        System.out.println("time to calc aberration: " + (System.currentTimeMillis() - start));
    }


    /**
     *  Description of the Method
     *
     *@param  value  Description of Parameter
     *@return        Description of the Returned Value
     */
    private Color calcColor(float value) {

        //value += 0.1;
        if (value < 0 || value > 1) {
            return Color.red;
        }
        /*
         *  if (value < 0) {
         *  return Color.red;
         *  }
         *  if (value > 1) {
         *  return Color.green;
         *  }
         */
        double c = (float) (((int) (value * 11)) / 11.0);
        c = ((-0.5 + c) * 0.7) + 0.5;
        return new Color((float) c, (float) c, (float) c);
    }


    /**
     *  Description of the Method
     *
     *@param  x  Description of Parameter
     *@param  y  Description of Parameter
     *@return    Description of the Returned Value
     */
    private float calcValue(double x, double y) {

        double r = Math.sqrt(x * x + y * y);
        double fi = Math.atan(y / x);

        // 90 grad drehen, anpassen an tableau
        fi -= Math.PI / 2;

        // 1. Quadrant
        if (x > 0 && y > 0) {
        }
        // 2. Quadrant
        if (x < 0 && y > 0) {
            fi += Math.PI;
        }
        // 3. Quadrant
        if (x < 0 && y < 0) {
            fi += Math.PI;
        }
        // 4. Quadrant
        if (x > 0 && y < 0) {
            fi += 2 * Math.PI;
        }

        double r3 = Math.pow(r, 3);
        double r2 = Math.pow(r, 2);

        return (float) (((((r2 * r2) / 4) -
                (delta / 2 * r2) -
                (deltaA / 2 * r2 * Math.cos(2 * (fi - fiA))) +
                (B * r3 * Math.cos(fi - fiB)) +
                (A3 * r3 * Math.cos(3 * (fi - fiA3)))) + 2.2) / 4.4);
    }

}

