From f0c7a3c02b2ab88af730c5abd735c8cda5276d03 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Wed, 23 Mar 2011 07:59:21 +0000 Subject: [PATCH] Improve GPX importer git-svn-id: https://svn.argeo.org/slc/trunk@4340 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../build.properties | 4 +- runtime/org.argeo.slc.support.gis/pom.xml | 3 +- .../main/java/org/argeo/slc/gpx/TrackDao.java | 2 +- .../java/org/argeo/slc/gpx/TrackSpeed.java | 60 +++++++++---- .../slc/gpx/hibernate/HibernateTrackDao.java | 47 ++++++++-- .../slc/gpx/hibernate/TrackSpeed.hbm.xml | 8 +- .../hibernate/HibernateTrackDaoTestCase.java | 90 ++++++++++++------- .../slc/gpx/hibernate/applicationContext.xml | 3 +- 8 files changed, 153 insertions(+), 64 deletions(-) diff --git a/runtime/org.argeo.slc.support.gis/build.properties b/runtime/org.argeo.slc.support.gis/build.properties index 7c9aa40a5..32b6e02ae 100644 --- a/runtime/org.argeo.slc.support.gis/build.properties +++ b/runtime/org.argeo.slc.support.gis/build.properties @@ -24,4 +24,6 @@ additional.bundles = com.springsource.slf4j.api,\ com.springsource.javax.transaction,\ org.argeo.dep.osgi.postgis.jdbc,\ com.springsource.org.apache.commons.collections,\ - com.springsource.javassist + com.springsource.javassist,\ + org.argeo.dep.osgi.hibernatespatial,\ + com.springsource.org.hibernate diff --git a/runtime/org.argeo.slc.support.gis/pom.xml b/runtime/org.argeo.slc.support.gis/pom.xml index ecbce95ff..4af047f4a 100644 --- a/runtime/org.argeo.slc.support.gis/pom.xml +++ b/runtime/org.argeo.slc.support.gis/pom.xml @@ -23,7 +23,8 @@ *, org.opengis.feature.simple, - org.argeo.slc.structure + org.argeo.slc.structure, + org.springframework.dao.support diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackDao.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackDao.java index 5a20baf1e..83c561e32 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackDao.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackDao.java @@ -3,5 +3,5 @@ package org.argeo.slc.gpx; import java.io.InputStream; public interface TrackDao { - public Object importTrackPoints(String sensor, InputStream in); + public Object importTrackPoints(String source, String sensor, InputStream in); } diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackSpeed.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackSpeed.java index 7e6bfd036..45241d9d2 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackSpeed.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/TrackSpeed.java @@ -2,6 +2,8 @@ package org.argeo.slc.gpx; import java.util.Date; +import org.geotools.referencing.GeodeticCalculator; + import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; @@ -10,29 +12,41 @@ public class TrackSpeed { private String segmentUuid; private String sensor; private Date utcTimestamp; - private Point location; + private Point position; private LineString line; - private Double length; + /** Orthodromic distance */ + private Double distance; + private Double azimuth; private Long duration; - // length(line)/(duration in h) + // orthodromicDistance(line) in km/(duration in h) private Double speed; // can be null private Double acceleration; + // can be null + private Double azimuthVariation; public TrackSpeed() { } - public TrackSpeed(TrackPoint ref, LineString line, Long duration) { + public TrackSpeed(TrackPoint ref, LineString line, Long duration, + GeodeticCalculator geodeticCalculator) { segmentUuid = ref.getSegmentUuid(); sensor = ref.getSensor(); utcTimestamp = ref.getUtcTimestamp(); - location = ref.getLocation(); + position = ref.getLocation(); this.line = line; this.duration = duration; - this.length = Math.abs(line.getLength()); + Point startPoint = line.getStartPoint(); + Point endPoint = line.getEndPoint(); + geodeticCalculator.setStartingGeographicPoint(startPoint.getX(), + startPoint.getY()); + geodeticCalculator.setDestinationGeographicPoint(endPoint.getX(), + endPoint.getY()); + this.distance = geodeticCalculator.getOrthodromicDistance(); + this.azimuth = geodeticCalculator.getAzimuth(); // in km/h - this.speed = (this.length * 60 * 60) / this.duration; + this.speed = (this.distance * 60 * 60) / this.duration; } public Integer getTid() { @@ -67,12 +81,12 @@ public class TrackSpeed { this.utcTimestamp = ts; } - public Point getLocation() { - return location; + public Point getPosition() { + return position; } - public void setLocation(Point location) { - this.location = location; + public void setPosition(Point location) { + this.position = location; } public LineString getLine() { @@ -99,12 +113,12 @@ public class TrackSpeed { this.speed = speed; } - public Double getLength() { - return length; + public Double getDistance() { + return distance; } - public void setLength(Double length) { - this.length = length; + public void setDistance(Double length) { + this.distance = length; } public Double getAcceleration() { @@ -115,4 +129,20 @@ public class TrackSpeed { this.acceleration = acceleration; } + public Double getAzimuth() { + return azimuth; + } + + public void setAzimuth(Double azimut) { + this.azimuth = azimut; + } + + public Double getAzimuthVariation() { + return azimuthVariation; + } + + public void setAzimuthVariation(Double azimuthVariation) { + this.azimuthVariation = azimuthVariation; + } + } diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/hibernate/HibernateTrackDao.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/hibernate/HibernateTrackDao.java index 6f7593bc6..855100c82 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/hibernate/HibernateTrackDao.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpx/hibernate/HibernateTrackDao.java @@ -21,6 +21,7 @@ import org.argeo.slc.gpx.TrackSegment; import org.argeo.slc.gpx.TrackSpeed; import org.geotools.geometry.DirectPosition2D; import org.geotools.referencing.CRS; +import org.geotools.referencing.GeodeticCalculator; import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; @@ -36,6 +37,12 @@ import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel; +/** + * Parses a GPX track file and import the data + * + * On PostGIS, a useful index is: + * CREATE INDEX track_speeds_line ON track_speeds USING GIST (line) + */ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { private final static Log log = LogFactory.getLog(HibernateTrackDao.class); private final static DateFormat ISO8601 = new SimpleDateFormat( @@ -43,15 +50,19 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { private Long batchSize = 100l; private Integer targetSrid = 4326; - private Float maxSpeed = 250f; + private Float maxSpeed = 200f; - public Object importTrackPoints(String sensor, InputStream in) { + private GeodeticCalculator geodeticCalculator; + + public Object importTrackPoints(String source, String sensor, InputStream in) { long begin = System.currentTimeMillis(); try { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(false); SAXParser sp = spf.newSAXParser(); InputSource input = new InputSource(in); + geodeticCalculator = new GeodeticCalculator(CRS.decode("EPSG:" + + targetSrid)); TrackGpxHandler handler = new TrackGpxHandler(sensor, targetSrid); sp.parse(input, handler); return null; @@ -60,8 +71,8 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { } finally { long duration = System.currentTimeMillis() - begin; if (log.isDebugEnabled()) - log.debug("Imported from sensor '" + sensor + "' in " - + (duration) + " ms"); + log.debug("Imported " + source + " from sensor '" + sensor + + "' in " + (duration) + " ms"); } } @@ -80,7 +91,7 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { if (i == trackSegment.getTrackPoints().size() - 1) trackSegment.setEndUtc(trackPoint.getUtcTimestamp()); else { - // SPEED + // order 1 coefficients (speed) TrackPoint next = trackSegment.getTrackPoints().get(i + 1); Coordinate[] crds = { trackPoint.getLocation().getCoordinate(), @@ -97,7 +108,7 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { continue trackPoints; } TrackSpeed trackSpeed = new TrackSpeed(trackPoint, line, - duration); + duration, geodeticCalculator); if (trackSpeed.getSpeed() > maxSpeed) { log.warn("Speed " + trackSpeed.getSpeed() + " is above " + maxSpeed + " between " + trackPoint.getLocation() @@ -107,15 +118,25 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { continue trackPoints; } + // order 2 coefficients (acceleration, azimuth variation) if (currentTrackSpeed != null) { - // in m/s² - Double speed1 = trackSpeed.getLength() + // compute acceleration (in m/s²) + Double speed1 = trackSpeed.getDistance() / (trackSpeed.getDuration() / 1000); - Double speed2 = currentTrackSpeed.getLength() + Double speed2 = currentTrackSpeed.getDistance() / (currentTrackSpeed.getDuration() / 1000); Double acceleration = (speed1 - speed2) / (currentTrackSpeed.getDuration() / 1000); trackSpeed.setAcceleration(acceleration); + + Double azimuthVariation = convertAzimuth(trackSpeed + .getAzimuth()) + - convertAzimuth(currentTrackSpeed.getAzimuth()); + if (azimuthVariation > 180) + azimuthVariation = -(360 - azimuthVariation); + else if (azimuthVariation < -180) + azimuthVariation = (360 + azimuthVariation); + trackSpeed.setAzimuthVariation(azimuthVariation); } trackSegment.getTrackSpeeds().add(trackSpeed); currentTrackSpeed = trackSpeed; @@ -128,6 +149,14 @@ public class HibernateTrackDao extends HibernateDaoSupport implements TrackDao { } + /** Normalize from [-180°,180°] to [0°,360°] */ + private Double convertAzimuth(Double azimuth) { + if (azimuth < 0) + return 360d + azimuth; + else + return azimuth; + } + public void setBatchSize(Long batchSize) { this.batchSize = batchSize; } diff --git a/runtime/org.argeo.slc.support.gis/src/main/resources/org/argeo/slc/gpx/hibernate/TrackSpeed.hbm.xml b/runtime/org.argeo.slc.support.gis/src/main/resources/org/argeo/slc/gpx/hibernate/TrackSpeed.hbm.xml index c3d3d6446..64a7f751f 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/resources/org/argeo/slc/gpx/hibernate/TrackSpeed.hbm.xml +++ b/runtime/org.argeo.slc.support.gis/src/main/resources/org/argeo/slc/gpx/hibernate/TrackSpeed.hbm.xml @@ -8,8 +8,8 @@ - - + + @@ -17,7 +17,9 @@ - + + + diff --git a/runtime/org.argeo.slc.support.gis/src/test/java/org/argeo/slc/gpx/hibernate/HibernateTrackDaoTestCase.java b/runtime/org.argeo.slc.support.gis/src/test/java/org/argeo/slc/gpx/hibernate/HibernateTrackDaoTestCase.java index 21d9121ce..415b91c2e 100644 --- a/runtime/org.argeo.slc.support.gis/src/test/java/org/argeo/slc/gpx/hibernate/HibernateTrackDaoTestCase.java +++ b/runtime/org.argeo.slc.support.gis/src/test/java/org/argeo/slc/gpx/hibernate/HibernateTrackDaoTestCase.java @@ -16,38 +16,62 @@ package org.argeo.slc.gpx.hibernate; +import java.io.File; +import java.io.FileInputStream; +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; -public class HibernateTrackDaoTestCase {//extends HibernateTestCase { -// static { -// HSConfiguration config = new HSConfiguration(); -// config.setDefaultDialect("org.hibernatespatial.postgis.PostgisDialect"); -// -// HBSpatialExtension.setConfiguration(config); -// } -// -// public void testImport() throws Exception { -// String sensor = "mbaudier"; -// File dir = new File("/home/mbaudier/ArgeoOffice/perso/gps/trips/2010"); -// -// TrackDao trackDao = getBean(TrackDao.class); -// long begin = System.currentTimeMillis(); -// for (File file : dir.listFiles()) { -// if (!file.getName().endsWith(".gpx")) -// continue; -// FileInputStream in = null; -// try { -// in = new FileInputStream(file); -// trackDao.importTrackPoints(sensor, in); -// } catch (Exception e) { -// log.warn("Could not import " + file + ": " + e.getMessage()); -// throw e; -// } finally { -// IOUtils.closeQuietly(in); -// } -// } -// double duration = System.currentTimeMillis() - begin; -// if (log.isDebugEnabled()) -// log.debug("Imported files from " + dir + " in " -// + (duration / 1000 / 60) + " min"); -// } +import org.apache.commons.io.IOUtils; +import org.argeo.slc.gpx.TrackDao; +import org.argeo.slc.hibernate.unit.HibernateTestCase; +import org.hibernatespatial.HBSpatialExtension; +import org.hibernatespatial.cfg.HSConfiguration; + +public class HibernateTrackDaoTestCase extends HibernateTestCase { + static { + HSConfiguration config = new HSConfiguration(); + config.setDefaultDialect("org.hibernatespatial.postgis.PostgisDialect"); + + HBSpatialExtension.setConfiguration(config); + } + + public void testImport() throws Exception { + String sensor = "mbaudier"; + File dir = new File("/home/mbaudier/ArgeoOffice/perso/gps/trips/2010"); + + SortedSet files = new TreeSet(new Comparator() { + public int compare(File o1, File o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + + TrackDao trackDao = getBean(TrackDao.class); + long begin = System.currentTimeMillis(); + + // order files + for (File file : dir.listFiles()) { + files.add(file); + } + + for (File file : files) { + if (!file.getName().endsWith(".gpx")) + continue; + FileInputStream in = null; + try { + in = new FileInputStream(file); + trackDao.importTrackPoints(file.getName(), sensor, in); + } catch (Exception e) { + log.warn("Could not import " + file + ": " + e.getMessage()); + throw e; + } finally { + IOUtils.closeQuietly(in); + } + } + long duration = System.currentTimeMillis() - begin; + if (log.isDebugEnabled()) + log.debug("Imported files from " + dir + " in " + + ((duration / 1000) / 60) + "min " + + ((duration / 1000) % 60) + "s"); + } } diff --git a/runtime/org.argeo.slc.support.gis/src/test/resources/org/argeo/slc/gpx/hibernate/applicationContext.xml b/runtime/org.argeo.slc.support.gis/src/test/resources/org/argeo/slc/gpx/hibernate/applicationContext.xml index 93218660b..3a4674e26 100644 --- a/runtime/org.argeo.slc.support.gis/src/test/resources/org/argeo/slc/gpx/hibernate/applicationContext.xml +++ b/runtime/org.argeo.slc.support.gis/src/test/resources/org/argeo/slc/gpx/hibernate/applicationContext.xml @@ -46,6 +46,7 @@ hibernate.jdbc.batch_size=100 - + + \ No newline at end of file -- 2.39.2