X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fdata%2FCoordinate.java;h=8b7904910b96e5da13445c7daa0aa352f15cdf41;hb=112bb0c9b46894adca9a33ed8c99ea712b253185;hp=7a572688ed2a0eb0eb63e6a3e6fda5f9037554d9;hpb=da0b1f449260a0b4a94318006382a9039726ef3e;p=GpsPrune.git diff --git a/tim/prune/data/Coordinate.java b/tim/prune/data/Coordinate.java index 7a57268..8b79049 100644 --- a/tim/prune/data/Coordinate.java +++ b/tim/prune/data/Coordinate.java @@ -1,5 +1,9 @@ package tim.prune.data; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + /** * Class to represent a lat/long coordinate * and provide conversion functions @@ -11,7 +15,7 @@ public abstract class Coordinate public static final int EAST = 1; public static final int SOUTH = 2; public static final int WEST = 3; - public static final char[] PRINTABLE_CARDINALS = {'N', 'E', 'S', 'W'}; + private static final char[] PRINTABLE_CARDINALS = {'N', 'E', 'S', 'W'}; public static final int FORMAT_DEG_MIN_SEC = 10; public static final int FORMAT_DEG_MIN = 11; public static final int FORMAT_DEG = 12; @@ -19,8 +23,16 @@ public abstract class Coordinate public static final int FORMAT_DEG_WHOLE_MIN = 14; public static final int FORMAT_DEG_MIN_SEC_WITH_SPACES = 15; public static final int FORMAT_CARDINAL = 16; + public static final int FORMAT_DECIMAL_FORCE_POINT = 17; public static final int FORMAT_NONE = 19; + /** Number formatter for fixed decimals with forced decimal point */ + private static final NumberFormat EIGHT_DP = NumberFormat.getNumberInstance(Locale.UK); + // Select the UK locale for this formatter so that decimal point is always used (not comma) + static { + if (EIGHT_DP instanceof DecimalFormat) ((DecimalFormat) EIGHT_DP).applyPattern("0.00000000"); + } + // Instance variables private boolean _valid = false; protected int _cardinal = NORTH; @@ -50,14 +62,21 @@ public abstract class Coordinate if (strLen > 1) { // Check for cardinal character either at beginning or end + boolean hasCardinal = true; _cardinal = getCardinal(inString.charAt(0), inString.charAt(strLen-1)); + if (_cardinal == NO_CARDINAL) { + hasCardinal = false; + // use default from concrete subclass + _cardinal = getDefaultCardinal(); + } + // count numeric fields - 1=d, 2=dm, 3=dm.m/dms, 4=dms.s int numFields = 0; boolean inNumeric = false; char currChar; long[] fields = new long[4]; // needs to be long for lengthy decimals long[] denoms = new long[4]; - String secondDelim = ""; + boolean[] otherDelims = new boolean[5]; // remember whether delimiters have non-decimal chars try { // Loop over characters in input string, populating fields array @@ -78,10 +97,8 @@ public abstract class Coordinate else { inNumeric = false; - // Remember second delimiter - if (numFields == 2) { - secondDelim += currChar; - } + // Remember delimiters + if (currChar != ',' && currChar != '.') {otherDelims[numFields] = true;} } } _valid = (numFields > 0); @@ -93,19 +110,32 @@ public abstract class Coordinate } // parse fields according to number found _degrees = (int) fields[0]; - _originalFormat = FORMAT_DEG; + _originalFormat = hasCardinal?FORMAT_DEG:FORMAT_DEG_WITHOUT_CARDINAL; _fracDenom = 10; if (numFields == 2) { - // String is just decimal degrees - double numMins = fields[1] * 60.0 / denoms[1]; - _minutes = (int) numMins; - double numSecs = (numMins - _minutes) * 60.0; - _seconds = (int) numSecs; - _fracs = (int) ((numSecs - _seconds) * 10); + if (!otherDelims[1]) + { + // String is just decimal degrees + double numMins = fields[1] * 60.0 / denoms[1]; + _minutes = (int) numMins; + double numSecs = (numMins - _minutes) * 60.0; + _seconds = (int) numSecs; + _fracs = (int) ((numSecs - _seconds) * 10); + _asDouble = _degrees + 1.0 * fields[1] / denoms[1]; + } + else + { + // String is degrees and minutes (due to non-decimal separator) + _originalFormat = FORMAT_DEG_MIN; + _minutes = (int) fields[1]; + _seconds = 0; + _fracs = 0; + _asDouble = 1.0 * _degrees + (_minutes / 60.0); + } } // Differentiate between d-m.f and d-m-s using . or , - else if (numFields == 3 && (secondDelim.equals(".") || secondDelim.equals(","))) + else if (numFields == 3 && !otherDelims[2]) { // String is degrees-minutes.fractions _originalFormat = FORMAT_DEG_MIN; @@ -113,6 +143,7 @@ public abstract class Coordinate double numSecs = fields[2] * 60.0 / denoms[2]; _seconds = (int) numSecs; _fracs = (int) ((numSecs - _seconds) * 10); + _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (numSecs / 3600.0); } else if (numFields == 4 || numFields == 3) { @@ -123,8 +154,8 @@ public abstract class Coordinate _fracs = (int) fields[3]; _fracDenom = (int) denoms[3]; if (_fracDenom < 1) {_fracDenom = 1;} + _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (_seconds / 3600.0) + (_fracs / 3600.0 / _fracDenom); } - _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (_seconds / 3600.0) + (_fracs / 3600.0 / _fracDenom); if (_cardinal == WEST || _cardinal == SOUTH || inString.charAt(0) == '-') _asDouble = -_asDouble; // validate fields @@ -147,10 +178,6 @@ public abstract class Coordinate if (cardinal == NO_CARDINAL) { cardinal = getCardinal(inLastChar); } - // use default from concrete subclass - if (cardinal == NO_CARDINAL) { - cardinal = getDefaultCardinal(); - } return cardinal; } @@ -248,7 +275,7 @@ public abstract class Coordinate { StringBuffer buffer = new StringBuffer(); buffer.append(PRINTABLE_CARDINALS[_cardinal]) - .append(threeDigitString(_degrees)).append('°') + .append(threeDigitString(_degrees)).append('\u00B0') .append(twoDigitString(_minutes)).append('\'') .append(twoDigitString(_seconds)).append('.') .append(formatFraction(_fracs, _fracDenom)); @@ -257,13 +284,13 @@ public abstract class Coordinate } case FORMAT_DEG_MIN: { - answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "°" + answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "\u00B0" + (_minutes + _seconds / 60.0 + _fracs / 60.0 / _fracDenom) + "'"; break; } case FORMAT_DEG_WHOLE_MIN: { - answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "°" + answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "\u00B0" + (int) Math.floor(_minutes + _seconds / 60.0 + _fracs / 60.0 / _fracDenom + 0.5) + "'"; break; } @@ -274,6 +301,12 @@ public abstract class Coordinate + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 3600.0 / _fracDenom); break; } + case FORMAT_DECIMAL_FORCE_POINT: + { + // Forcing a decimal point instead of system-dependent commas etc + answer = EIGHT_DP.format(_asDouble); + break; + } case FORMAT_DEG_MIN_SEC_WITH_SPACES: { // Note: cardinal not needed as this format is only for exif, which has cardinal separately