package com.github.pfichtner.jrunalyser.ui.map.util;
import static com.github.pfichtner.jrunalyser.base.data.stat.Functions.Metadatas.maxLatitude;
import static com.github.pfichtner.jrunalyser.base.data.stat.Functions.Metadatas.maxLongitude;
import static com.github.pfichtner.jrunalyser.base.data.stat.Functions.Metadatas.minLatitude;
import static com.github.pfichtner.jrunalyser.base.data.stat.Functions.Metadatas.minLongitude;
import static com.github.pfichtner.jrunalyser.base.data.stat.Functions.Tracks.metadata;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.jdesktop.swingx.JXMapKit;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.mapviewer.TileFactory;
import org.jdesktop.swingx.mapviewer.TileFactoryInfo;
import com.github.pfichtner.jrunalyser.base.data.WayPoint;
import com.github.pfichtner.jrunalyser.base.data.track.Metadata;
import com.github.pfichtner.jrunalyser.base.data.track.Track;
import com.github.pfichtner.jrunalyser.base.stat.Boxplot;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.primitives.Doubles;
public final class GeoUtil {
private GeoUtil() {
super();
}
public enum CenterType {
AVERAGE {
@Override
public double avg(Iterable<Double> doubles) {
double sum = 0.0;
int cnt = 0;
for (Double d : doubles) {
sum += d.doubleValue();
cnt++;
}
return cnt > 0 ? sum / cnt : 0.0;
}
},
BOXPLOT_AVERAGE {
@Override
public double avg(Iterable<Double> doubles) {
Boxplot boxplot = new Boxplot(Lists.newArrayList(doubles));
return AVERAGE.avg(Doubles.asList(boxplot.getValues(boxplot
.outerFences())));
}
};
public abstract double avg(Iterable<Double> transform);
}
public static Rectangle2D getBounds(Track track, JXMapViewer jxMapViewer) {
return getBounds(track, jxMapViewer.getZoom(),
jxMapViewer.getTileFactory());
}
public static Rectangle2D getBounds(Track track, int zoomLevel,
TileFactory tileFactory) {
TileFactoryInfo info = tileFactory.getInfo();
double minLat = track.getMetadata().getMinLatitude();
double minLng = track.getMetadata().getMinLongitude();
double maxLat = track.getMetadata().getMaxLatitude();
double maxLng = track.getMetadata().getMaxLongitude();
Point2D nw = org.jdesktop.swingx.mapviewer.util.GeoUtil
.getBitmapCoordinate(minLat, minLng, zoomLevel, info);
Point2D se = org.jdesktop.swingx.mapviewer.util.GeoUtil
.getBitmapCoordinate(maxLat, maxLng, zoomLevel, info);
double mx = Math.min(nw.getX(), se.getX());
double my = Math.min(nw.getY(), se.getY());
double mw = Math.max(nw.getX(), se.getX()) - mx;
double mh = Math.max(nw.getY(), se.getY()) - my;
return new Rectangle2D.Double(mx, my, mw, mh);
}
public static GeoPosition calcCenter(Track track) {
Metadata md = track.getMetadata();
double lat1 = md.getMinLatitude();
double lng1 = md.getMinLongitude();
double lat2 = md.getMaxLatitude();
double lng2 = md.getMaxLongitude();
return calcCenter(lat1, lng1, lat2, lng2);
}
public static GeoPosition calcCenter(Iterable<Track> tracks,
CenterType centerType) {
FluentIterable<Metadata> metadatas = FluentIterable.from(tracks)
.transform(metadata);
double lat1 = centerType.avg(metadatas.transform(minLatitude));
double lng1 = centerType.avg(metadatas.transform(minLongitude));
double lat2 = centerType.avg(metadatas.transform(maxLatitude));
double lng2 = centerType.avg(metadatas.transform(maxLongitude));
return calcCenter(lat1, lng1, lat2, lng2);
}
private static GeoPosition calcCenter(double lat1, double lng1,
double lat2, double lng2) {
return new GeoPosition((lat1 + lat2) / 2, (lng1 + lng2) / 2);
}
public static int calcMaxZoomLevel(JXMapKit mapKit, Track track) {
JXMapViewer mapViewer = mapKit.getMainMap();
int mmw = mapViewer.getWidth();
int mmh = mapViewer.getHeight();
TileFactory tileFactory = mapViewer.getTileFactory();
int maximumZoomLevel = tileFactory.getInfo().getMaximumZoomLevel();
int minimumZoomLevel = tileFactory.getInfo().getMinimumZoomLevel();
for (int i = maximumZoomLevel; i >= minimumZoomLevel; i--) {
Rectangle2D tr = getBounds(track, i, tileFactory);
if (tr.getWidth() > mmw || tr.getHeight() > mmh) {
return i + 1;
}
}
return minimumZoomLevel;
}
public static GeoPosition toGeoPoint(WayPoint trackPoint) {
return new GeoPosition(trackPoint.getLatitude(),
trackPoint.getLongitude());
}
}