package AstroOL; import java.util.Vector; import java.util.Enumeration; /** Wrapperklasse für Sexagesimalzahlen. Ähnlich wie java.lang.Double ist AstroOL.Degree eine umhüllende Klasse (Wrapperklasse) für eine doppeltgenaue Gleitkommazahl (<code>double</code>). Eine Instanz dieser Klasse repräsentiert eine Angabe im Sexagesimalsystem (Position im Tierkreis, Uhrzeit, geographische Längen- oder Breitenangabe). Sie enthält Methoden zum Einlesen (Parsen) von sexagesimalen Zahlen sowie zur Ausgabe in einem geeigneten Format. */ public class Degree { /** Genauigkeit Minuten oder Sekunden - Default Sekunden */ public static boolean minutesOnly = false; /** Runden - Default ja */ public static boolean round = true; /** Intern ist ein Objekt dieser Klasse einfach ein double, repräsentiert den Wert <code>value</code> */ private double decimalValue; /** Instanz zum Wert 0 bilden (leerer Konstruktor). */ public Degree() { this(0d); } /** Konstruktor für bekannte Gleitommazahl */ public Degree(double x) { int circle = 360; decimalValue = x; if ( x < 0 ) circle = -circle; while ( decimalValue < 0 || decimalValue >= circle) decimalValue -= circle; } /** Kopier-Konstruktor */ public Degree(Degree d) { this( d.decimalValue ); } /** Zuerst Sexagesimalzahl parsen */ public Degree(String s) { decimalValue = getValue(s); } /** Getter-Methode für zugrundeliegende Gleitkommazahl */ public double getValue() { return decimalValue; } /** Eine Sexagesimalzahl interpretieren */ public static double getValue(String s) { StringBuffer prefix = new StringBuffer(); long numerator = 0, denominator = 1; int i = 0; boolean first = true, negative = false; Vector number = new Vector(3), delimiter = new Vector(3); Integer element; double x; parse( s, prefix, number, delimiter ); Enumeration e = number.elements(); x = 0d; while (e.hasMoreElements()) { numerator = numerator * 60 + ((Integer)e.nextElement()).intValue(); if (first) { if (numerator < 0) { negative = true; numerator = -numerator; } first = false; } else denominator *= 60; } if (negative) numerator = -numerator; x = (double) numerator / denominator; if (delimiter.size() > 0) { // Tierkreiszeichen-Kurzform interpretieren i = -1; if ((i = signNumber(delimiter.elementAt(0).toString())) < 0 ) if ( (delimiter.size() == 3) && ((i = signNumber(delimiter.elementAt(2).toString())) < 0)) if (delimiter.size() == 2) i = signNumber(delimiter.elementAt(1).toString()); if ((i >= 0) ) x = Calculator.fmod360(x + (negative ? -30*i : 30*i)); else if ("ws".indexOf(delimiter.elementAt(0).toString().toLowerCase()) >=0) x = (negative) ? x : -x; } return x; } /** Nummer des Tierkreiszeichens (AR = 0, TA = 1, ...) ermitteln */ public static int signNumber(String sign) { if (sign.length() != 2) return -1; int i = Calculator.sknam.indexOf(sign.toUpperCase()); if ((i%2)!=0) return -1; else return i/2; } /** Ausgabefunktion - identisch zu dms() */ public String toString() { return dms(decimalValue, "°", "'", "\"", minutesOnly, round); } /** Einen String erzeugen, der die Sexagesimalzahl dieses Objekts darstellt. */ public String dms() { return dms(decimalValue,"°", "'", "\"", minutesOnly, round); } /** Einen String erzeugen, der die übergebene Sexagesimalzahl darstellt. */ public static String dms(double x) { return dms(x, "°", "'", "\"", minutesOnly, round); } /** Einen String erzeugen, der die übergebene Sexagesimalzahl darstellt; Trennzeichen oder -string für die Gradzahl ist frei wählbar. */ public static String dms(double x, String DegDel) { return dms(x, DegDel, "'", "\"", minutesOnly, round); } /** Einen String erzeugen, der die übergebene Sexagesimalzahl darstellt; Trennzeichen oder -strings zwischen den Zahlwerten für Grade, Minuten und Sekunden sind frei wählbar. */ public static String dms(double x, String DegreeDel, String MinDel, String SecDel) { return dms(x, DegreeDel, MinDel, SecDel, minutesOnly, round); } /** Einen String in eine alternierende Sequenz von Zahl und Nicht-Zahl zerlegen. Die Zerlegung geschieht nach folgendem Muster: <pre> // NotANumber Number NotANumber Number NotANumber ... // (prefix) number(1) delimiter(1) number(2) delimiter(2) ... </pre> */ public static void parse( String in, StringBuffer prefix, Vector number, Vector delimiter ) { int i, j, l, lastcut = 0; boolean first = true, wasNumeric = false, isNumeric = false; StringBuffer delim = new StringBuffer(1); char c = ' '; prefix.setLength(0); l = in.length(); for( i = 0; i <= l; i++ ) { if (i < l) { c = in.charAt(i); c = Character.toUpperCase(c); if (Character.isWhitespace(c)) continue; isNumeric = Character.isDigit(c); } // Typsprung? if (i != 0 && (isNumeric != wasNumeric) || (i == l)) { if (wasNumeric) { number.addElement(new Integer(delim.toString())); } else if (first) { prefix.append(delim.toString()); } else { delimiter.addElement(delim); } lastcut = i; delim = new StringBuffer(1); first = false; } delim.append(c); wasNumeric = isNumeric; } } /** Einen Gradwert als String mit frei wählbaren Trennzeichen zwischen den Zahlwerten für Grade, Minuten und Sekunden darstellen. Darüberhinaus kann bestimmt werden, ob die Darstellung nur minutengenau sein soll und ob gerundet werden soll. */ public static String dms(double x, String DegreeDel, String MinDel, String SecDel, boolean minutesOnly, boolean round) { String result; double lx; int d; byte m,s; char sign; // Lokale Kopie erstellen, da Wert verändert wird lx = x; // Vorzeichen merken, Absolutwert nehmen if ( lx < 0 ) { sign = '-'; lx = -lx; } else sign = ' '; // Runden? Dann .5' oder .5" addieren if (round) if (minutesOnly) // Sicherstellen, dass auch für exakt .5' oder .5" // gerundet wird: Kleine Zahl hinzuzählen lx += .5d/60 + 1.e-12d; else lx += .5d/3600 + 1.e-12d; // Grade ermitteln, in Ergebnis schieben d = (int) lx; if (d < 10) result = " " + sign + d; else if (d < 100) result = " " + sign + d; else result = sign + "" + d; // Grad-Suffix result = result + DegreeDel; // Minuten m = (byte) ( ( lx - d ) * 60 ); if (m < 10) result = result + " " + m; else result = result + m; // Minuten-Suffix result = result + MinDel; // Sekunden s = (byte) ( (( lx - d ) * 60 - m ) * 60. ); if (!minutesOnly) { if (s < 10) result = result + " " + s; else result = result + s; // Sekunden-Suffix result = result + SecDel; } return result; } /** Die dieses Objekt repräsentierende Gleitkommazahl als zodiakalen Längenwert darstellen. */ public String zodLength() { return zodLength(decimalValue); } /** Die mit dem Aufruf übergebene Gleitkommazahl als zodiakalen Längenwert darstellen. */ public static String zodLength(double x) { double x1; int offset; x1 = ( x/360 - Math.floor(x/360))*360; offset = ((int) x1 / 30)*2; x1 = ( x1/30d - Math.floor(x1/30d))*30; if (x1 >= 29.99986111) { x1 = 0; offset = (offset+2) % 12; } return dms(x1) + Calculator.sknam.substring(offset,offset+2); } } // Class Degree