package org.sigmah.shared.map;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
/**
* @author Alex Bertram (akbertram@gmail.com)
*/
public abstract class AbstractCoordinateEditor {
protected String posHemiChars;
protected String negHemiChars;
protected String decimalSeperators;
protected String noNumberErrorMessage;
protected String tooManyNumbersErrorMessage;
protected String noHemisphereMessage;
protected String invalidSecondsMessage;
protected String invalidMinutesMessage;
protected double minValue = -180.0;
protected double maxValue = +180.0;
public enum Notation {
DDd,
DMd,
DMS
}
protected Notation notation = Notation.DMS;
protected abstract Double parseDouble(String s);
protected abstract String formatDDd(double value);
protected abstract String formatShortFrac(double value);
protected abstract String formatInt(double value);
public Double parse(String value) throws CoordinateFormatException {
if(value == null) {
return null;
}
StringBuffer tokens[] = new StringBuffer[] {
new StringBuffer(),
new StringBuffer(),
new StringBuffer() };
int tokenIndex = 0;
int i;
/*
* To assure correctness, we're going to insist that the
* user explicitly enter the hemisphere (+/-/N/S).
*
* However, if the bounds dictate that the coordinate is
* in one hemisphere, then we can assume the assign.
*
*/
double sign = 0;
if(maxValue < 0) {
sign = -1;
} else if(minValue > 0) {
sign = +1;
}
for(i = 0; i!=value.length(); ++i) {
char c = value.charAt(i);
if(c == '-' || negHemiChars.indexOf(c) != -1) {
sign = -1;
} else if(c == '+' || posHemiChars.indexOf(c) != -1) {
sign = 1;
} else if(Character.isDigit(c) || decimalSeperators.indexOf(c) != -1) {
if(tokenIndex > 2) {
throw new CoordinateFormatException(tooManyNumbersErrorMessage);
}
tokens[tokenIndex].append(c);
} else if(tokenIndex !=2 && tokens[tokenIndex].length() > 0) {
tokenIndex++;
}
}
if(sign == 0) {
throw new CoordinateFormatException(noHemisphereMessage);
}
if(tokens[0].length() == 0) {
throw new CoordinateFormatException(noNumberErrorMessage);
}
double coordinate = Double.parseDouble(tokens[0].toString());
notation = Notation.DDd;
if(tokens[1].length() != 0) {
double minutes = parseDouble(tokens[1].toString());
if(minutes < 0 || minutes > 60.0) {
throw new CoordinateFormatException(invalidMinutesMessage);
}
coordinate += minutes / 60.0;
notation = Notation.DMd;
}
if(tokens[2].length() != 0) {
double seconds = parseDouble(tokens[2].toString());
if(seconds < 0.0 || seconds > 60.0) {
throw new CoordinateFormatException(invalidSecondsMessage);
}
notation = Notation.DMS;
coordinate += seconds / 3600.0;
}
return coordinate * sign;
}
/**
* Converts a coordinate value into Degree-Minute-decimal notation
*
* @param value
* @return An array of three double values : { sign, degrees, minutes }
*/
public static double[] convertToDMd(double value) {
double degrees = Math.floor(Math.abs(value));
double minutes = (Math.abs(value)-degrees);
return new double[] { Math.signum(value), degrees, minutes } ;
}
/**
* Converts a coordinate value into Degree-Minute-Second notation
*
* @param value
* @return An array of four double values: { sign, degrees, minutes, seconds }
*/
public static double[] convertToDMS(double value) {
double absv = Math.abs(value);
double degrees = Math.floor(absv);
double minutes = ((absv - degrees) * 60.0);
double seconds = ((minutes - Math.floor(minutes)) * 60.0);
minutes = Math.floor(minutes);
return new double[] { Math.signum(value), degrees, minutes, seconds };
}
public String format(double coordinate) {
if(notation == Notation.DDd) {
return formatDDd(coordinate);
} else {
StringBuilder sb = new StringBuilder();
double DMS[];
if (notation == Notation.DMd) {
DMS = convertToDMd(coordinate);
sb.append(formatInt(Math.abs(DMS[1]))).append("° ");
sb.append(formatShortFrac(DMS[2])).append("' ");
} else {
DMS = convertToDMS(coordinate);
sb.append(formatInt(Math.abs(DMS[1]))).append("° ");
sb.append(formatInt(DMS[2])).append("' ");
sb.append(formatShortFrac(DMS[3])).append("\" ");
}
if(DMS[0] < 0) {
sb.append(negHemiChars.charAt(0));
} else {
sb.append(posHemiChars.charAt(0));
}
return sb.toString();
}
}
public double getMinValue() {
return minValue;
}
public void setMinValue(double minValue) {
this.minValue = minValue;
}
public double getMaxValue() {
return maxValue;
}
public void setMaxValue(double maxValue) {
this.maxValue = maxValue;
}
public Notation getNotation() {
return notation;
}
public void setNotation(Notation notation) {
this.notation = notation;
}
}