From 5b16b58e1c14bfe168cd3e1a5e63ef5f58e525e6 Mon Sep 17 00:00:00 2001 From: erik Date: Tue, 1 Aug 2006 11:49:51 +0000 Subject: [PATCH 1/1] --- gps/src/org/wamblee/gpx/CoordinateSystem.java | 30 ++++ gps/src/org/wamblee/gpx/Coordinates.java | 51 +++++++ gps/src/org/wamblee/gpx/GpxPlotter.java | 142 ++++++++++++++++++ gps/src/org/wamblee/gpx/Point.java | 54 +++++++ .../gpx/ReferenceCoordinateSystem.java | 69 +++++++++ .../gpx/SphericalCoordinateSystem.java | 60 ++++++++ gps/src/org/wamblee/gpx/Track.java | 60 ++++++++ gps/src/org/wamblee/gpx/TrackPoint.java | 36 +++++ .../wamblee/gpx/Wgs84CoordinateSystem.java | 70 +++++++++ 9 files changed, 572 insertions(+) create mode 100644 gps/src/org/wamblee/gpx/CoordinateSystem.java create mode 100644 gps/src/org/wamblee/gpx/Coordinates.java create mode 100644 gps/src/org/wamblee/gpx/GpxPlotter.java create mode 100644 gps/src/org/wamblee/gpx/Point.java create mode 100644 gps/src/org/wamblee/gpx/ReferenceCoordinateSystem.java create mode 100644 gps/src/org/wamblee/gpx/SphericalCoordinateSystem.java create mode 100644 gps/src/org/wamblee/gpx/Track.java create mode 100644 gps/src/org/wamblee/gpx/TrackPoint.java create mode 100644 gps/src/org/wamblee/gpx/Wgs84CoordinateSystem.java diff --git a/gps/src/org/wamblee/gpx/CoordinateSystem.java b/gps/src/org/wamblee/gpx/CoordinateSystem.java new file mode 100644 index 00000000..c88b8069 --- /dev/null +++ b/gps/src/org/wamblee/gpx/CoordinateSystem.java @@ -0,0 +1,30 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +/** + * Represents a coordinate system. + */ +public interface CoordinateSystem { + + /** + * Conversion to a reference coordinate system. + * @param aCoordinates Coordinates. + * @return Coordinates in the reference system. + */ + Coordinates toReferenceSystem(Coordinates aCoordinates); +} diff --git a/gps/src/org/wamblee/gpx/Coordinates.java b/gps/src/org/wamblee/gpx/Coordinates.java new file mode 100644 index 00000000..cfca9dd5 --- /dev/null +++ b/gps/src/org/wamblee/gpx/Coordinates.java @@ -0,0 +1,51 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +/** + * Coordinates in some 3-dimensional coordinate system. + */ +public class Coordinates { + + private double _x1; + private double _x2; + private double _x3; + + /** + * Constructs the coordinates. + * @param aX1 First coordinate. + * @param aX2 Second coordinate. + * @param aX3 Third coordinate. + */ + public Coordinates(double aX1, double aX2, double aX3) { + _x1 = aX1; + _x2 = aX2; + _x3 = aX3; + } + + public double getX1() { + return _x1; + } + + public double getX2() { + return _x2; + } + + public double getX3() { + return _x3; + } +} diff --git a/gps/src/org/wamblee/gpx/GpxPlotter.java b/gps/src/org/wamblee/gpx/GpxPlotter.java new file mode 100644 index 00000000..8cb03a19 --- /dev/null +++ b/gps/src/org/wamblee/gpx/GpxPlotter.java @@ -0,0 +1,142 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; + +import org.dom4j.Document; +import org.dom4j.Element; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartFrame; +import org.jfree.chart.ChartUtilities; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.wamblee.general.Pair; +import org.wamblee.xml.DomUtils; +import org.xml.sax.SAXException; + +/** + * Parses a GPX file and prints out a data file with each trackpoints distance from the start of the + * track and its elevation, separated by a space. + */ +public class GpxPlotter { + + public static void main(String[] aArgs) throws ParserConfigurationException, FileNotFoundException, SAXException, IOException { + File file = new File(aArgs[0]); + Document doc = DomUtils.convert(DomUtils.read(new FileInputStream(file))); + + Track track = parseTrack(doc); + + List> elevationProfile = computeElevationProfile(track); + printTrack(elevationProfile); + computeTotalClimb(elevationProfile); + plotElevationProfile(elevationProfile); + } + + /** + * @param doc + */ + private static Track parseTrack(Document doc) { + Track track = new Track(); + Element root = doc.getRootElement().element("trk").element("trkseg"); + for ( Iterator i =root.elementIterator("trkpt"); i.hasNext(); ) { + Element trkpt = (Element)i.next(); + track.addPoint(parseTrackPoint(trkpt)); + } + return track; + } + + /** + * @param trkpt + */ + private static TrackPoint parseTrackPoint(Element trkpt) { + //System.out.println(trkpt.asXML() + "|\n"); + double latitude = new Double(trkpt.attributeValue("lat")); + double longitude = new Double(trkpt.attributeValue("lon")); + double elevation = new Double(trkpt.elementText("ele")); + //System.out.println(" lat = " + lat + " lon = " + lon + " ele = " + ele); + return new TrackPoint(latitude, longitude, elevation); + } + + private static List> computeElevationProfile(Track aTrack) { + List> results = new ArrayList>(); + double distance = 0.0; + for (int i = 0; i < aTrack.size(); i++) { + Point point = aTrack.getPoint(i); + results.add(new Pair(distance, point.getCoordinates().getX3())); + if ( i+1 < aTrack.size()) { + Point nextPoint = aTrack.getPoint(i+1); + distance += ReferenceCoordinateSystem.distance(point, nextPoint); + } + } + return results; + } + + private static void printTrack(List> aHeightProfile) { + for (Pair point: aHeightProfile) { + System.out.println(point.getFirst() + " " + point.getSecond()); + } + } + + private static void computeTotalClimb(List> aHeightProfile) { + double result = 0.0; + + double lastHeight = aHeightProfile.get(0).getSecond(); + for ( int i = 1; i < aHeightProfile.size(); i++) { + double height = aHeightProfile.get(i).getSecond(); + if ( height > lastHeight) { + result += (height-lastHeight); + } + lastHeight = height; + } + System.out.println("Total climb: " + result); + } + + private static void plotElevationProfile(List> aHeightProfile) throws IOException { + XYSeries series = new XYSeries("height"); + for (Pair point: aHeightProfile) { + series.add(point.getFirst(), point.getSecond()); + } + XYSeriesCollection dataset = new XYSeriesCollection(series); + JFreeChart chart = ChartFactory.createXYLineChart( + "Height Profile", + "Distance(m)", + "Height(m)", + dataset, + PlotOrientation.VERTICAL, + true, + true, + false); + ChartUtilities.writeChartAsPNG(new FileOutputStream("test.png"), chart, 600, 300); + ChartFrame frame = new ChartFrame("test", chart); + frame.pack(); + frame.setVisible(true); + } + +} + diff --git a/gps/src/org/wamblee/gpx/Point.java b/gps/src/org/wamblee/gpx/Point.java new file mode 100644 index 00000000..d04ec861 --- /dev/null +++ b/gps/src/org/wamblee/gpx/Point.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +/** + * Represents a point in some coordinate system. + */ +public class Point { + + private Coordinates _coordinates; + private CoordinateSystem _system; + + /** + * Constructs the point. + * @param aCoordinates Coordinates of the point in its coordinate system. + * @param aSystem Coordinate system. + */ + public Point(Coordinates aCoordinates, CoordinateSystem aSystem) { + _coordinates = aCoordinates; + _system = aSystem; + } + + /** + * Gets the coordinates in the point's coordinate system. + * @return Coordinates. + */ + public Coordinates getCoordinates() { + return _coordinates; + } + + /** + * Gets the coordinate system. + * @return Coordinate system. + */ + public CoordinateSystem getCoordinateSystem() { + return _system; + } + + +} diff --git a/gps/src/org/wamblee/gpx/ReferenceCoordinateSystem.java b/gps/src/org/wamblee/gpx/ReferenceCoordinateSystem.java new file mode 100644 index 00000000..7c4afb45 --- /dev/null +++ b/gps/src/org/wamblee/gpx/ReferenceCoordinateSystem.java @@ -0,0 +1,69 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +/** + * Reference coordinate system which is the basis for defining metrics. + * This is a Cartesian coordinate system. + */ +public class ReferenceCoordinateSystem implements CoordinateSystem { + + /** + * Constructs the coordinate system. + * + */ + public ReferenceCoordinateSystem() { + // Empty + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.gpx.CoordinateSystem#toReferenceSystem(org.wamblee.gpx.Coordinates) + */ + public Coordinates toReferenceSystem(Coordinates aCoordinates) { + return aCoordinates; + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.gpx.CoordinateSystem#distance(org.wamblee.gpx.Coordinates, + * org.wamblee.gpx.Coordinates) + */ + private static double distance(Coordinates aC1, Coordinates aC2) { + return Math.sqrt(square(aC1.getX1() - aC2.getX1()) + + square(aC1.getX2() - aC2.getX2()) + + square(aC1.getX3() - aC2.getX3())); + } + + private static double square(double x) { + return x * x; + } + + /** + * Computes the distance between two points in arbitrary coordinate systems. + * @param aP1 First point. + * @param aP2 Second point. + * @return Distance. + */ + public static double distance(Point aP1, Point aP2) { + return distance( aP1.getCoordinateSystem().toReferenceSystem(aP1.getCoordinates()), + aP2.getCoordinateSystem().toReferenceSystem(aP2.getCoordinates())); + } + +} diff --git a/gps/src/org/wamblee/gpx/SphericalCoordinateSystem.java b/gps/src/org/wamblee/gpx/SphericalCoordinateSystem.java new file mode 100644 index 00000000..607c0a49 --- /dev/null +++ b/gps/src/org/wamblee/gpx/SphericalCoordinateSystem.java @@ -0,0 +1,60 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +import static java.lang.Math.PI; +import static java.lang.Math.cos; +import static java.lang.Math.sin; + +/** + * Represents the coordinate system for a GPS measurement identified by + *
    + *
  • x1: latitude in degrees
  • + *
  • x2: longitude in degrees
  • + *
  • x3: elevation in meters
  • + *
+ * This coordinate system models the earth as a sphere of a specific radius. + */ +public class SphericalCoordinateSystem implements CoordinateSystem { + /** + * Earth radius in meters. + */ + private static final double EARTH_RADIUS = 6371000; + + + /* (non-Javadoc) + * @see org.wamblee.gpx.CoordinateSystem#toReferenceSystem(org.wamblee.gpx.Coordinates) + */ + public Coordinates toReferenceSystem(Coordinates aCoordinates) { + double latrad = radians(aCoordinates.getX1()); + double lonrad = radians(aCoordinates.getX2()); + double coslat = cos(latrad); + double sinlat = sin(latrad); + double coslon = cos(lonrad); + double sinlon = sin(lonrad); + + double trueElevation = EARTH_RADIUS + aCoordinates.getX3(); + return new Coordinates(trueElevation*coslat*coslon, + trueElevation*coslat*sinlon, + trueElevation*sinlat); + + } + + private double radians(double aDegrees) { + return aDegrees/180.0*PI; + } +} diff --git a/gps/src/org/wamblee/gpx/Track.java b/gps/src/org/wamblee/gpx/Track.java new file mode 100644 index 00000000..5d253293 --- /dev/null +++ b/gps/src/org/wamblee/gpx/Track.java @@ -0,0 +1,60 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a GPS track. + */ +public class Track { + + private List _points; + + /** + * Constructs an empty track. + * + */ + public Track() { + _points = new ArrayList(); + } + + /** + * Adds a point to a track. + * @param aPoint Point. + */ + public void addPoint(TrackPoint aPoint) { + _points.add(aPoint); + } + + /** + * @return Number of points in the track. + */ + public int size() { + return _points.size(); + } + + /** + * Gets the point at the given inded. + * @param aIndex 0 <= aIndex < size() + * @return Point. + */ + public Point getPoint(int aIndex) { + return _points.get(aIndex); + } +} diff --git a/gps/src/org/wamblee/gpx/TrackPoint.java b/gps/src/org/wamblee/gpx/TrackPoint.java new file mode 100644 index 00000000..9be99bfc --- /dev/null +++ b/gps/src/org/wamblee/gpx/TrackPoint.java @@ -0,0 +1,36 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + + +/** + * A point from a GPS track. + * + * TODO should be extended with additional information (e.g. date/time if available). + */ +public class TrackPoint extends Point { + + /** + * Constructs the point. + * @param aLatitude Latitude in degrees. + * @param aLongitude Longitude in degrees. + * @param aElevation Elevation in metres. + */ + public TrackPoint(double aLatitude, double aLongitude, double aElevation) { + super(new Coordinates(aLatitude, aLongitude, aElevation), new Wgs84CoordinateSystem()); + } +} diff --git a/gps/src/org/wamblee/gpx/Wgs84CoordinateSystem.java b/gps/src/org/wamblee/gpx/Wgs84CoordinateSystem.java new file mode 100644 index 00000000..94f7ba7b --- /dev/null +++ b/gps/src/org/wamblee/gpx/Wgs84CoordinateSystem.java @@ -0,0 +1,70 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wamblee.gpx; + +import static java.lang.Math.PI; +import static java.lang.Math.cos; +import static java.lang.Math.sin; + +/** + * Represents the WGS 84 coordinate system for a GPS measurement identified by + *
    + *
  • x1: latitude in degrees
  • + *
  • x2: longitude in degrees
  • + *
  • x3: elevation in meters
  • + *
+ * WGS84 models the earth as an ellipse. + */ +public class Wgs84CoordinateSystem implements CoordinateSystem { + /* + * Ellipse parameters + */ + + /** + * The radius of the ellipse at the equator + */ + private static final double A = 6378137.000; + + /** + * The distance of the North and South poles to the center of the ellipse. + */ + private static final double B = 6356752.314; + + + /* (non-Javadoc) + * @see org.wamblee.gpx.CoordinateSystem#toReferenceSystem(org.wamblee.gpx.Coordinates) + */ + public Coordinates toReferenceSystem(Coordinates aCoordinates) { + double latrad = radians(aCoordinates.getX1()); + double lonrad = radians(aCoordinates.getX2()); + double coslat = cos(latrad); + double sinlat = sin(latrad); + double coslon = cos(lonrad); + double sinlon = sin(lonrad); + + double r = A*B/Math.sqrt(B*B*coslat*coslat + A*A*sinlat*sinlat) + aCoordinates.getX3(); + + return new Coordinates(r*coslat*coslon, + r*coslat*sinlon, + r*sinlat); + + } + + private double radians(double aDegrees) { + return aDegrees/180.0*PI; + } +} -- 2.31.1