static {
if (EIGHT_DP instanceof DecimalFormat) ((DecimalFormat) EIGHT_DP).applyPattern("0.00000000");
}
+ /** Number formatter for fixed decimals with forced decimal point */
+ private static final NumberFormat FIVE_DP = NumberFormat.getNumberInstance(Locale.UK);
+ static {
+ if (FIVE_DP instanceof DecimalFormat) ((DecimalFormat) FIVE_DP).applyPattern("0.00000");
+ }
// Instance variables
private boolean _valid = false;
inString = inString.trim();
strLen = inString.length();
}
- if (strLen > 1)
+ if (strLen > 0)
{
// Check for cardinal character either at beginning or end
boolean hasCardinal = true;
// count numeric fields - 1=d, 2=dm, 3=dm.m/dms, 4=dms.s
int numFields = 0;
- boolean inNumeric = false;
+ boolean isNumeric = false;
char currChar;
long[] fields = new long[4]; // needs to be long for lengthy decimals
long[] denoms = new long[4];
currChar = inString.charAt(i);
if (currChar >= '0' && currChar <= '9')
{
- if (!inNumeric)
+ if (!isNumeric)
{
- inNumeric = true;
+ isNumeric = true;
numFields++;
denoms[numFields-1] = 1;
}
- fields[numFields-1] = fields[numFields-1] * 10 + (currChar - '0');
- denoms[numFields-1] *= 10;
+ if (denoms[numFields-1] < 1E18) // ignore trailing characters if too big for long
+ {
+ fields[numFields-1] = fields[numFields-1] * 10 + (currChar - '0');
+ denoms[numFields-1] *= 10;
+ }
}
else
{
- inNumeric = false;
+ isNumeric = false;
// Remember delimiters
if (currChar != ',' && currChar != '.') {otherDelims[numFields] = true;}
}
}
// parse fields according to number found
_degrees = (int) fields[0];
- _originalFormat = hasCardinal?FORMAT_DEG:FORMAT_DEG_WITHOUT_CARDINAL;
+ _asDouble = _degrees;
+ _originalFormat = hasCardinal ? FORMAT_DEG : FORMAT_DEG_WITHOUT_CARDINAL;
_fracDenom = 10;
if (numFields == 2)
{
_asDouble = 1.0 * _degrees + (_minutes / 60.0);
}
}
+ // Check for exponential degrees like 1.3E-6
+ else if (numFields == 3 && !otherDelims[1] && otherDelims[2] && isJustNumber(inString))
+ {
+ _originalFormat = FORMAT_DEG;
+ _asDouble = Math.abs(Double.parseDouble(inString)); // must succeed if isJustNumber has given true
+ // now we can ignore the fields and just use this double
+ _degrees = (int) _asDouble;
+ double numMins = (_asDouble - _degrees) * 60.0;
+ _minutes = (int) numMins;
+ double numSecs = (numMins - _minutes) * 60.0;
+ _seconds = (int) numSecs;
+ _fracs = (int) ((numSecs - _seconds) * 10);
+ }
// Differentiate between d-m.f and d-m-s using . or ,
else if (numFields == 3 && !otherDelims[2])
{
if (_cardinal == WEST || _cardinal == SOUTH || inString.charAt(0) == '-')
_asDouble = -_asDouble;
// validate fields
- _valid = _valid && (_degrees <= getMaxDegrees() && _minutes < 60 && _seconds < 60 && _fracs < _fracDenom);
+ _valid = _valid && (_degrees <= getMaxDegrees() && _minutes < 60 && _seconds < 60 && _fracs < _fracDenom)
+ && Math.abs(_asDouble) <= getMaxDegrees();
}
else _valid = false;
}
/**
* Get the cardinal from the given character
- * @param inFirstChar first character from file
- * @param inLastChar last character from file
+ * @param inFirstChar first character from string
+ * @param inLastChar last character from string
*/
- protected int getCardinal(char inFirstChar, char inLastChar)
+ private int getCardinal(char inFirstChar, char inLastChar)
{
// Try leading character first
int cardinal = getCardinal(inFirstChar);
*/
public boolean equals(Coordinate inOther)
{
- return (inOther != null && _cardinal == inOther._cardinal
- && _degrees == inOther._degrees
- && _minutes == inOther._minutes
- && _seconds == inOther._seconds
- && _fracs == inOther._fracs);
+ return (_asDouble == inOther._asDouble);
}
case FORMAT_DEG_MIN:
{
answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "\u00B0"
- + (_minutes + _seconds / 60.0 + _fracs / 60.0 / _fracDenom) + "'";
+ + FIVE_DP.format((Math.abs(_asDouble) - _degrees) * 60.0) + "'";
break;
}
case FORMAT_DEG_WHOLE_MIN:
{
- answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "\u00B0"
- + (int) Math.floor(_minutes + _seconds / 60.0 + _fracs / 60.0 / _fracDenom + 0.5) + "'";
+ int deg = _degrees;
+ int min = (int) Math.floor(_minutes + _seconds / 60.0 + _fracs / 60.0 / _fracDenom + 0.5);
+ if (min == 60) {
+ min = 0; deg++;
+ }
+ answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(deg) + "\u00B0" + min + "'";
break;
}
case FORMAT_DEG:
case FORMAT_DEG_WITHOUT_CARDINAL:
{
- answer = (_asDouble<0.0?"-":"")
- + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 3600.0 / _fracDenom);
+ if (_originalFormat != FORMAT_DEG_WITHOUT_CARDINAL)
+ {
+ answer = (_asDouble<0.0?"-":"")
+ + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 3600.0 / _fracDenom);
+ }
break;
}
case FORMAT_DECIMAL_FORCE_POINT:
double startValue = inStart.getDouble();
double endValue = inEnd.getDouble();
double newValue = startValue + (endValue - startValue) * inFraction;
- Coordinate answer = inStart.makeNew(newValue, inStart._originalFormat);
+ Coordinate answer = inStart.makeNew(newValue, Coordinate.FORMAT_DECIMAL_FORCE_POINT);
return answer;
}