package net.sourceforge.gpstools.utils;
/* gpxconv
* Copyright (C) 2006 Moritz Ringler
* $Id: GpsFormat.java 441 2010-12-13 20:04:20Z ringler $
*
* 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/>.
*/
import java.io.IOException;
import java.text.ChoiceFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
public class GpsFormat{
private static GpsFormat me;
private final NumberFormat FORMAT_LAT_LON;
private final NumberFormat FORMAT_ALT;
/** Result is N if latitude value >= 0, S otherwise **/
private final NumberFormat FORMAT_LAT_REF;
/** Result is W if longitude is < 0 and E otherwise. **/
private final NumberFormat FORMAT_LON_REF;
private GpsFormat(){
DecimalFormat df = new DecimalFormat("#0.000000");
DecimalFormatSymbols sym = df.getDecimalFormatSymbols();
sym.setDecimalSeparator('.');
df.setDecimalFormatSymbols(sym);
FORMAT_LAT_LON = df;
df = new DecimalFormat("#0.00");
sym = df.getDecimalFormatSymbols();
sym.setDecimalSeparator('.');
df.setDecimalFormatSymbols(sym);
FORMAT_ALT = df;
final double[] posneg = new double[]{Double.NEGATIVE_INFINITY, 0};
FORMAT_LAT_REF = new ChoiceFormat(posneg, new String[]{"S", "N"});
FORMAT_LON_REF = new ChoiceFormat(posneg, new String[]{"W", "E"});
}
public static synchronized GpsFormat getInstance(){
if(me == null){
me = new GpsFormat();
}
return me;
}
/** Result is N if latitude value >= 0, S otherwise **/
public String asLatRef(Number n){
synchronized(FORMAT_LAT_REF){
return FORMAT_LAT_REF.format(n);
}
}
/** Result is W if longitude is < 0 and E otherwise. **/
public String asLonRef(Number n){
synchronized(FORMAT_LON_REF){
return FORMAT_LON_REF.format(n);
}
}
public String asAltitude(Number number){
synchronized(FORMAT_ALT){
return FORMAT_ALT.format(number);
}
}
public String asLatLon(Number number){
synchronized(FORMAT_LAT_LON){
return FORMAT_LAT_LON.format(number);
}
}
public String asLatLon(Number lat, Number lon){
synchronized(FORMAT_LAT_LON){
return FORMAT_LAT_LON.format(lat) + ',' + FORMAT_LAT_LON.format(lon);
}
}
public String asGPolylineCoordinate(Number current, Number previous){
StringBuilder result = new StringBuilder();
try{
asGPolylineCoordinate(current, previous, result);
} catch (IOException wonthappen){
wonthappen.printStackTrace();
}
return result.toString();
}
public Appendable asGPolylineCoordinate(Number current, Number previous, Appendable sb) throws IOException{
double a = current.doubleValue();
if(previous != null){
a = a - previous.doubleValue();
}
return gEncodeDouble(a, sb);
}
private Appendable gEncodeDouble(double d, Appendable a) throws IOException{
// Instead of Math.floor as suggested in the doc we use Math.round
// to avoid the systematic error inherent to flooring
return gEncodeInt((int) Math.round(d * 1e5), a);
}
private Appendable gEncodeInt(int num, Appendable a) throws IOException{
int sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return gEncodeUnsignedInt(sgn_num, a);
}
public Appendable gEncodeUnsignedInt(int n, Appendable a) throws IOException{
int num = n;
char c;
while (num >= 0x20) {
c = (char) ((0x20 | (num & 0x1f)) + 63);
a.append(c);
// if the encoded value is a backslash escape it with another one
// see http://tinyurl.com/yhc3ta
if(c == '\\'){
a.append(c);
}
num >>= 5;
}
c = (char) (num + 63);
a.append(c);
// if the encoded value is a backslash escape it with another one
// see http://tinyurl.com/yhc3ta
if(c == '\\'){
a.append(c);
}
return a;
}
@Override
public Object clone() throws CloneNotSupportedException {
//forbid cloning this singleton
throw new CloneNotSupportedException();
}
public static void main(String argv[]) throws Exception{
StringBuilder sb = new StringBuilder();
for(String arg : argv){
GpsFormat.getInstance().gEncodeInt((int) Math.round(1e5 *Double.parseDouble(arg)), sb);
sb.append("\n");
}
System.out.println(sb);
}
}