package net.sourceforge.gpstools.utils;
/* gpsdings
* Copyright (C) 2006 Moritz Ringler
* $Id: GPXUtils.java 445 2011-01-17 21:26:27Z 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.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.TimeZone;
import net.sourceforge.gpstools.gpx.BoundsType;
import net.sourceforge.gpstools.gpx.GpxType;
import net.sourceforge.gpstools.gpx.MetadataType;
import net.sourceforge.gpstools.gpx.Trk;
import net.sourceforge.gpstools.gpx.Trkseg;
import net.sourceforge.gpstools.gpx.TrksegType;
import net.sourceforge.gpstools.gpx.Wpt;
import net.sourceforge.gpstools.gpx.WptType;
import org.geonames.WebService;
public class GPXUtils{
private static GPXUtils me;
private String[] timeZoneIDs;
private GPXUtils(){
//disallow instantiation
}
public static synchronized GPXUtils getInstance(){
if(me == null){
me = new GPXUtils();
}
return me;
}
@Override
public Object clone() throws CloneNotSupportedException {
//forbid cloning this singleton
throw new CloneNotSupportedException();
}
private synchronized String[] getTimeZoneIDs(){
if(timeZoneIDs == null){
timeZoneIDs = TimeZone.getAvailableIDs();
Arrays.sort(timeZoneIDs);
}
return timeZoneIDs;
}
public void copyProperties(Wpt from, Wpt to){
to.setName(from.getName());
to.setLat(from.getLat().setScale(6, RoundingMode.HALF_UP));
to.setLon(from.getLon().setScale(6, RoundingMode.HALF_UP));
to.setEle(from.getEle().setScale(6, RoundingMode.HALF_UP));
to.setCmt(from.getCmt());
to.setDesc(from.getDesc());
to.setSym(from.getSym());
Date d = from.getTime();
to.setTime(d);
}
public Wpt copyWpt(Wpt pt){
Wpt result = new Wpt();
copyProperties(pt, result);
return result;
}
private TimeZone getTimeZone(BoundsType bounds) throws TimeZoneBoundaryException, GeonamesException{
WptType pt = new Wpt();
pt.setLat(bounds.getMinlat());
pt.setLon(bounds.getMinlon());
final TimeZone result = getTimeZone(pt);
if(result == null){
return null;
}
pt.setLon(bounds.getMaxlon());
TimeZone check = getTimeZone(pt);
if(!result.equals(check)){
throw new TimeZoneBoundaryException(bounds);
}
pt.setLat(bounds.getMaxlat());
check = getTimeZone(pt);
if(!result.equals(check)){
throw new TimeZoneBoundaryException(bounds);
}
pt.setLon(bounds.getMinlon());
check = getTimeZone(pt);
if(!result.equals(check)){
throw new TimeZoneBoundaryException(bounds);
}
return result;
}
private TimeZone getTimeZone(TrksegType trk) throws TimeZoneBoundaryException, GeonamesException{
final int n = trk.getTrkptCount();
switch(n){
case 0: return null;
case 1: return getTimeZone(trk.getTrkpt(0));
default:
TimeZone result = getTimeZone(trk.getTrkpt(0));
if(result == null){
return null;
}
TimeZone check = getTimeZone(trk.getTrkpt(n-1));
if(!result.equals(check)){
throw new TimeZoneBoundaryException(trk);
}
return result;
}
}
public TimeZone getTimeZone(GpxType gpx) throws TimeZoneBoundaryException, GeonamesException{
MetadataType meta = gpx.getMetadata();
if(meta != null){
BoundsType bounds = meta.getBounds();
if(bounds != null){
return getTimeZone(bounds);
}
//}
//no bounds found, try first wpt
//if(gpx.getWptCount() > 0){
// return getTimeZone(gpx.getWpt(0));
//no wpts try trk
} else {
Iterator<? extends Trk> trks = gpx.iterateTrk();
while(trks.hasNext()){
Iterator<? extends Trkseg> segs = trks.next().iterateTrkseg();
while(segs.hasNext()){
TimeZone result = getTimeZone(segs.next());
if(result != null){
return result;
}
}
}
}
return null;
}
public TimeZone getTimeZone(WptType pt) throws GeonamesException{
org.geonames.Timezone geoTz = null;
try{
geoTz = WebService.timezone(pt.getLat().doubleValue(), pt.getLon().doubleValue());
} catch (Exception ex){
throw new GeonamesException(ex);
}
if(geoTz == null){
return null;
}
String tzID = geoTz.getTimezoneId();
return (Arrays.binarySearch(getTimeZoneIDs(), tzID) < 0)
? null
: TimeZone.getTimeZone(tzID);
}
public void setEle(WptType[] pts)
throws GeonamesException
{
int requestsize = 20;
double[] lat = new double[requestsize];
double[] lon = new double[requestsize];
Arrays.fill(lat, 0.0);
Arrays.fill(lon, 0.0);
for (int i = 0; i < pts.length; i++)
{
int k = i % requestsize;
lat[k] = pts[i].getLat().doubleValue();
lon[k] = pts[i].getLon().doubleValue();
if (k == requestsize - 1 || i == pts.length - 1)
{
int[] ele;
try
{
ele = WebService.srtm3(lat, lon);
}
catch (Exception ex)
{
throw new GeonamesException(ex);
}
for (int j = 0; j <= k; j++)
{
pts[i - k + j].setEle(new BigDecimal(ele[j]));
}
}
}
}
public static class TimeZoneBoundaryException extends Exception{
/**
*
*/
private static final long serialVersionUID = 8350000172502836962L;
private final Object data;
public TimeZoneBoundaryException(Object offendingdata){
super("Geo-data from more than one timezone.");
data = offendingdata;
}
public Object getOffendingData(){
return data;
}
}
public static class GeonamesException extends Exception{
/**
*
*/
private static final long serialVersionUID = -1356542772115677300L;
public GeonamesException(Throwable cause){
super(cause);
}
}
}