de.thkwalter.et.ortskurve.Startpunktbestimmung.java Source code

Java tutorial

Introduction

Here is the source code for de.thkwalter.et.ortskurve.Startpunktbestimmung.java

Source

/**
 *  Copyright 2013 Th. K. Walter, Nrnberg.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package de.thkwalter.et.ortskurve;

import java.util.ArrayList;
import java.util.logging.Logger;

import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;
import org.apache.commons.math3.linear.SingularMatrixException;

import de.thkwalter.jsf.ApplicationRuntimeException;

/**
 * Diese Klasse berechnet aus drei Punkten den Startpunkt fr das Ausgleichsproblem. 
 *
 * @author Th. K. Walter
 */
public class Startpunktbestimmung {
    /*
     * Der Logger dieser Klasse.
     */
    private static Logger logger = Logger.getLogger(Startpunktbestimmung.class.getName());

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Dieser Konstruktor bestimmt aus den Messpunkten den Startpunkt fr die nichtlineare Ausgleichsrechnung.
     * 
     * @param messpunkte Das Feld der Messpunkte
     */
    public static double[] startpunktBerechnen(Vector2D[] messpunkte) {
        // Falls weniger als drei Messpunkte existieren, wird eine JSFAusnahme geworfen.
        if (messpunkte == null || messpunkte.length < 3) {
            // Die Anzahl der Messpunkte wird bestimmt.
            int anzahlMesspunkte = messpunkte == null ? 0 : messpunkte.length;

            // Die Fehlermeldung fr den Entwickler wird erzeugt und protokolliert.
            String fehlermeldung = "Es existieren nur " + anzahlMesspunkte + " Messpunkte!";
            Startpunktbestimmung.logger.severe(fehlermeldung);

            // Die Ausnahme wird erzeugt und mit der Fehlermeldung fr den Benutzer initialisiert.
            String jsfMeldung = "Um einen Kreis berechnen zu knnen, werden mindestens drei Messpunkte bentigt. "
                    + "Es stehen jedoch nur " + anzahlMesspunkte + " Messpunkte zur Verfgung! "
                    + "Fgen Sie bitte weitere Messpunkte hinzu.";
            ApplicationRuntimeException applicationRuntimeException = new ApplicationRuntimeException(jsfMeldung);

            throw applicationRuntimeException;
        }

        // Die Messpunkte, die zur Startpunktbestimmung verwendet werden
        Vector2D[] messpunkteZurStartpunktbestimmung = null;

        // Falls nur drei Messpunkte existieren, werden diese zur Startpunktbestimmung verwendet.
        if (messpunkte.length == 3) {
            messpunkteZurStartpunktbestimmung = messpunkte;
        }

        // Falls mehr als drei Messpunkte existieren, wird bestimmt, welche davon zur Startpunktbestimmung verwendet werden.
        else {
            // Die Messpunkte, die zur Startpunktbestimmung verwendet werden, werden ausgewhlt.
            messpunkteZurStartpunktbestimmung = Startpunktbestimmung.messpunkteAuswaehlen(messpunkte);
        }

        // Der Startpunkt wird bestimmt.
        return Startpunktbestimmung.startpunktBestimmen(messpunkteZurStartpunktbestimmung);
    }

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Diese Methode berechnet den Startpunkt aus den ersten drei Messpunkten.
     * 
     * @return Der Startpunkt. Die erste Komponente des Feldes reprsentiert die x-Komponente des Mittelpunktes, die zweite
     * Komponente die y-Komponente, die dritte Komponente den Radius.
     */
    private static double[] startpunktBestimmen(Vector2D[] messpunkteZurStartpunktbestimmung) {
        // Die Felder fr die Koeffizientenmatrix und die Inhomogenitt werden definiert.
        double[][] koeffizienten = new double[3][];
        double[] inhomogenitaet = new double[3];

        // Einige Hilfsgren werden deklariert.
        double[] zeile = null;
        double x = Double.NaN;
        double y = Double.NaN;

        // In der folgenden Schleife werden die Koeffizientenmatrix und die Inhomogenitt initialisiert.
        for (int i = 0; i < 3; i++) {
            // Die x- und y-Komponente eines Punktes werden gelesen.
            x = messpunkteZurStartpunktbestimmung[i].getX();
            y = messpunkteZurStartpunktbestimmung[i].getY();

            // Eine Zeile der Koeffizientenmatrix wird initialisiert
            zeile = new double[3];
            zeile[0] = 1;
            zeile[1] = -x;
            zeile[2] = -y;
            koeffizienten[i] = zeile;

            // Eine Komponente des Inhomogenittsvektors wird initialisiert.
            inhomogenitaet[i] = -(x * x + y * y);
        }

        // Die Koeffizientenmatrix wird erzeugt.
        RealMatrix koeffizientenmatrix = new Array2DRowRealMatrix(koeffizienten);

        // Der Inhomogenittsvektor wird erzeugt.
        RealVector inhomogenitaetsvektor = new ArrayRealVector(inhomogenitaet, false);

        // Der Lsungsalgorithmus fr das lineare Gleichungssystem wird erzeugt.
        DecompositionSolver alorithmus = new LUDecomposition(koeffizientenmatrix).getSolver();

        // Das inhomogene Gleichungssystem wird gelst.
        RealVector loesung = null;
        try {
            loesung = alorithmus.solve(inhomogenitaetsvektor);
        } catch (SingularMatrixException singularMatrixException) {
            // Die Fehlermeldung fr den Entwickler wird erzeugt und protokolliert.
            String fehlermeldung = "Die Matrix aus den Punkten " + messpunkteZurStartpunktbestimmung[0] + ", "
                    + messpunkteZurStartpunktbestimmung[1] + " und " + messpunkteZurStartpunktbestimmung[2]
                    + " ist singulr.";
            Startpunktbestimmung.logger.severe(fehlermeldung);

            // Die Ausnahme wird erzeugt und mit der Fehlermeldung fr den Benutzer initialisiert.
            String jsfMeldung = "Eine von den Messpunkten (" + messpunkteZurStartpunktbestimmung[0].getX() + ", "
                    + messpunkteZurStartpunktbestimmung[0].getY() + "), ("
                    + messpunkteZurStartpunktbestimmung[1].getX() + ", "
                    + messpunkteZurStartpunktbestimmung[1].getY() + ") und ("
                    + messpunkteZurStartpunktbestimmung[2].getX() + ", "
                    + messpunkteZurStartpunktbestimmung[2].getY() + ")" + " abhngige Matrix ist singur. Der "
                    + "Berechnungsalgorithmus bentigt jedoch eine regulre Matrix! Entfernen Sie bitte einen der oben "
                    + "angegebenen Messpunkte.";
            ApplicationRuntimeException applicationRuntimeException = new ApplicationRuntimeException(jsfMeldung);

            throw applicationRuntimeException;
        }

        // Der Startpunkt wird aus der Lsung des linearen Gleichungssystems bestimmt.
        double xMittelpunkt = 0.5 * loesung.getEntry(1);
        double yMittelpunkt = 0.5 * loesung.getEntry(2);
        double radius = Math.sqrt(xMittelpunkt * xMittelpunkt + yMittelpunkt * yMittelpunkt - loesung.getEntry(0));

        // Der Startpunkt wird zurckgegeben.
        return new double[] { xMittelpunkt, yMittelpunkt, radius };
    }

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Diese Methode bestimmt die Messpunkte, die zur Startpunktbestimmung verwendet werden. Das sind die beiden
     * Messpunkte mit dem grten bzw. kleinsten y-Komponente (Realteil des Stroms) und der Messpunkt, dessen y-Komponente 
     * am nhesten zum Mittelwert aus der grten und der kleinsten auftreteten y-Komponente liegt.
     */
    private static Vector2D[] messpunkteAuswaehlen(Vector2D[] messpunkte) {
        // Zwei Listen mit den Messpunkten werden erstellt.
        ArrayList<XKomponenteMesspunkt> xListe = new ArrayList<XKomponenteMesspunkt>();
        ArrayList<YKomponenteMesspunkt> yListe = new ArrayList<YKomponenteMesspunkt>();

        // Die Listen werden mit den Messpunkten initialisiert.
        for (Vector2D messpunkt : messpunkte) {
            xListe.add(new XKomponenteMesspunkt(messpunkt));
            yListe.add(new YKomponenteMesspunkt(messpunkt));
        }

        // Die Messpunkte mit der grten und kleinsten x-Komponente werden bestimmt.
        Vector2D maxXMesspunkt = Startpunktbestimmung.maxMesspunktBestimmen(xListe);
        Vector2D minXMesspunkt = Startpunktbestimmung.minMesspunktBestimmen(xListe);

        // Die Messpunkte mit der grten und kleinsten y-Komponente werden bestimmt.
        Vector2D maxYMesspunkt = Startpunktbestimmung.maxMesspunktBestimmen(yListe);
        Vector2D minYMesspunkt = Startpunktbestimmung.minMesspunktBestimmen(yListe);

        // Die Messpunkte, die bei der Startpunktbestimmung verwendet werden, werden deklariert.
        Vector2D maxMesspunkt = null;
        Vector2D minMesspunkt = null;
        Vector2D mittlererMesspunkt = null;

        // Falls der Wertebereich der x-Komponente der Messpunkte grer ist als der Wertebereich der y-Komponente, ...
        if (maxXMesspunkt.getX() - minXMesspunkt.getX() > maxYMesspunkt.getY() - minYMesspunkt.getY()) {
            // Die Messpunkte mit der grten und kleinsten x-Kompomnente werden bei der Startpunktbestimmung verwendet.
            maxMesspunkt = maxXMesspunkt;
            minMesspunkt = minXMesspunkt;
            mittlererMesspunkt = Startpunktbestimmung.mittlerenMesspunktBestimmen(xListe,
                    0.5 * (maxXMesspunkt.getX() + minXMesspunkt.getX()));
        }

        // Falls der Wertebereich der x-Komponente der Messpunkte nicht grer ist als der Wertebereich der y-Komponente, ...
        else {
            // Die Messpunkte mit der grten und kleinsten y-Kompomnente werden bei der Startpunktbestimmung verwendet.
            maxMesspunkt = maxYMesspunkt;
            minMesspunkt = minYMesspunkt;
            mittlererMesspunkt = Startpunktbestimmung.mittlerenMesspunktBestimmen(yListe,
                    0.5 * (maxYMesspunkt.getY() + minYMesspunkt.getY()));
        }

        // Die Messpunkte, die zur Startpunktbestimmung verwendet werden, werden zurckgegeben.
        return new Vector2D[] { maxMesspunkt, minMesspunkt, mittlererMesspunkt };
    }

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Diese Methode bestimmt den Messpunkt, dessen x- bzw. y-Komponente am nhesten zum Mittelwert aus der grten und der 
     * kleinsten auftreteten x- bzw. y-Komponente liegt. 
     * 
     * @param messpunkte Eine Liste der x- bzw. y-Komponenten der Messpunkte
     * @param mittelwert Der Mittelwert aus der grten und der kleinsten auftreteten x- bzw. y-Komponente
     * 
     * @return Der Messpunkt, dessen x- bzw. y-Komponente am nhesten zum Mittelwert aus der grten und der 
     * kleinsten auftreteten x- bzw. y-Komponente liegt
     */
    private static Vector2D mittlerenMesspunktBestimmen(ArrayList<? extends KomponenteMesspunkt> liste,
            double mittelwert) {
        // Der gesuchte Messpunkt.
        KomponenteMesspunkt mittlereKomponenteMesspunkt = null;

        // Der kleinste bisher gefundene Abstand der x- bzw. y-Komponente eines Messpunkts zum Mittelwert.
        double minAbstandZumMittelwert = Double.POSITIVE_INFINITY;

        // Der Abstand der x- bzw. y-Komponente eines Messpunkts zum Mittelwert.
        double abstandZumMittelwert = Double.NaN;

        // Eine Schleife ber alle Messpunkte.
        for (KomponenteMesspunkt komponenteMesspunkt : liste) {
            // Der Abstand der x- bzw. y-Komponente eines Messpunkts zum Mittelwert wird berechnet.
            abstandZumMittelwert = Math.abs(komponenteMesspunkt.getWert() - mittelwert);

            // Falls der Abstand der x- bzw. y-Komponente des aktuellen Messpunkts zum Mittelwert kleiner als das bisherige 
            // Minimum ist, ...
            if (abstandZumMittelwert < minAbstandZumMittelwert) {
                // Der minimale Abstand der x- bzw. y-Komponente eines Messpunkts zum Mittelwert wird aktualisiert.
                minAbstandZumMittelwert = abstandZumMittelwert;

                // Der gesuchte Punkt wird aktualisiert.
                mittlereKomponenteMesspunkt = komponenteMesspunkt;
            }
        }

        // Der gesuchte Messpunkt wird zurckgegeben.
        return mittlereKomponenteMesspunkt.getMesspunkt();
    }

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Diese Methode bestimmt den Messpunkt mit dem grten Wert der x- bzw. y-Komponente.
     * 
     * @param liste Eine Liste der x- bzw. y-Komponenten der Messpunkte
     * 
     * @return Der Messpunkt mit dem grten Wert der x- bzw. y-Komponente
     */
    private static Vector2D maxMesspunktBestimmen(ArrayList<? extends KomponenteMesspunkt> liste) {
        // Die Messpunkte mit der grten x- bzw. y-Komponente.
        KomponenteMesspunkt maxKomponenteMesspunkt = null;

        // Die x- bzw. y-Komponente eines Messwertes.
        double wert = Double.NaN;

        // Die grte bisher gefundene x- bzw. y-Komponente.
        double maxWert = Double.NEGATIVE_INFINITY;

        // Eine Schleife ber alle Messpunkte in der Liste
        for (KomponenteMesspunkt komponenteMesspunkt : liste) {
            // Die x- bzw. y-Komponente des Messpunktes wird gelesen.
            wert = komponenteMesspunkt.getWert();

            // Falls die x- bzw. y-Komponente des Messpunkts grer als die grte bisher gefundene x- bzw. y-Komponente, ...
            if (wert > maxWert) {
                // Die grte bisher gefundene x- bzw. y-Komponente wird aktualisiert.  
                maxWert = wert;

                // Der Messpunkt mit der grten x- bzw. y-Komponente wird aktualisiert.
                maxKomponenteMesspunkt = komponenteMesspunkt;
            }
        }

        // Der Messpunkt mit der grten x- bzw. y-Komponente wird aus der Liste entfernt.
        liste.remove(maxKomponenteMesspunkt);

        // Der Messpunkt mit der grten x- bzw. y-Komponente wird zurckgegeben.
        return maxKomponenteMesspunkt.getMesspunkt();
    }

    // =====================================================================================================================
    // =====================================================================================================================

    /**
     * Diese Methode bestimmt den Messpunkt mit dem kleinsten Wert der x- bzw. y-Komponente.
     * 
     * @param liste Eine Liste der x- bzw. y-Komponenten der Messpunkte
     * 
     * @return Der Messpunkt mit dem kleinstenbgh Wert der x- bzw. y-Komponente
     */
    private static Vector2D minMesspunktBestimmen(ArrayList<? extends KomponenteMesspunkt> liste) {
        // Die Messpunkte mit der kleinsten x- bzw. y-Komponente.
        KomponenteMesspunkt minKomponenteMesspunkt = null;

        // Die x- bzw. y-Komponente eines Messwertes.
        double wert = Double.NaN;

        // Die kleinste bisher gefundene x- bzw. y-Komponente.
        double minWert = Double.POSITIVE_INFINITY;

        // Eine Schleife ber alle Messpunkte in der Liste
        for (KomponenteMesspunkt komponenteMesspunkt : liste) {
            // Die x- bzw. y-Komponente des Messpunktes wird gelesen.
            wert = komponenteMesspunkt.getWert();

            // Falls die x- bzw. y-Komponente des Messpunkts kleiner als die kleinste bisher gefundene x- bzw. y-Komponente, ...
            if (wert < minWert) {
                // Die grte bisher gefundene x- bzw. y-Komponente wird aktualisiert.  
                minWert = wert;

                // Der Messpunkt mit der kleinsten x- bzw. y-Komponente wird aktualisiert.
                minKomponenteMesspunkt = komponenteMesspunkt;
            }
        }

        // Der Messpunkt mit der kleinsten x- bzw. y-Komponente wird aus der Liste entfernt.
        liste.remove(minKomponenteMesspunkt);

        // Der Messpunkt mit der grten x- bzw. y-Komponente wird zurckgegeben.
        return minKomponenteMesspunkt.getMesspunkt();
    }
}