001/*
002 * Shredzone Commons - suncalc
003 *
004 * Copyright (C) 2017 Richard "Shred" Körber
005 *   http://commons.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.commons.suncalc.util;
015
016import static java.lang.Math.abs;
017import static java.lang.Math.sqrt;
018
019/**
020 * Calculates the roots and extremum of a quadratic equation.
021 */
022public class QuadraticInterpolation {
023
024    private final double xe;
025    private final double ye;
026    private final double root1;
027    private final double root2;
028    private final int nRoot;
029    private final boolean maximum;
030
031    /**
032     * Creates a new quadratic equation.
033     *
034     * @param yMinus
035     *            y at x == -1
036     * @param y0
037     *            y at x == 0
038     * @param yPlus
039     *            y at x == 1
040     */
041    public QuadraticInterpolation(double yMinus, double y0, double yPlus) {
042        double a = 0.5 * (yPlus + yMinus) - y0;
043        double b = 0.5 * (yPlus - yMinus);
044        double c = y0;
045
046        xe = -b / (2.0 * a);
047        ye = (a * xe + b) * xe + c;
048        maximum = a < 0.0;
049        double dis = b * b - 4.0 * a * c;
050
051        int rootCount = 0;
052
053        if (dis >= 0.0) {
054            double dx = 0.5 * sqrt(dis) / abs(a);
055            root1 = xe - dx;
056            root2 = xe + dx;
057
058            if (abs(root1) <= 1.0) {
059                rootCount++;
060            }
061
062            if (abs(root2) <= 1.0) {
063                rootCount++;
064            }
065        } else {
066            root1 = Double.NaN;
067            root2 = Double.NaN;
068        }
069
070        nRoot = rootCount;
071    }
072
073    /**
074     * Returns X of extremum. Can be outside [-1 .. 1].
075     *
076     * @return X
077     */
078    public double getXe() {
079        return xe;
080    }
081
082    /**
083     * Returns the Y value at the extremum.
084     *
085     * @return Y
086     */
087    public double getYe() {
088        return ye;
089    }
090
091    /**
092     * Returns the first root that was found.
093     *
094     * @return X of first root
095     */
096    public double getRoot1() {
097        return root1 < -1.0 ? root2 : root1;
098    }
099
100    /**
101     * Returns the second root that was found.
102     *
103     * @return X of second root
104     */
105    public double getRoot2() {
106        return root2;
107    }
108
109    /**
110     * Returns the number of roots found in [-1 .. 1].
111     *
112     * @return Number of roots
113     */
114    public int getNumberOfRoots() {
115        return nRoot;
116    }
117
118    /**
119     * Returns whether the extremum is a minimum or a maximum.
120     *
121     * @return {@code true}: Extremum at xe is a maximum. {@code false}: Extremum at xe is
122     *         a minimum.
123     */
124    public boolean isMaximum() {
125        return maximum;
126    }
127
128}