/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2016 HydroloGIS (www.hydrologis.com) * * 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/>. */ package eu.geopaparazzi.core.database.objects; import android.location.Location; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import eu.geopaparazzi.library.gpx.GpxRepresenter; import eu.geopaparazzi.library.gpx.GpxUtilities; import eu.geopaparazzi.library.kml.KmlRepresenter; import eu.geopaparazzi.library.style.ColorUtilities; import eu.geopaparazzi.library.util.DynamicDoubleArray; import eu.geopaparazzi.library.util.TimeUtilities; import eu.geopaparazzi.library.util.Utilities; import static java.lang.Math.abs; import static java.lang.Math.pow; import static java.lang.Math.sqrt; /** * Represents a line (log or map). * * @author Andrea Antonello (www.hydrologis.com) */ public class Line implements KmlRepresenter, GpxRepresenter, Serializable { private String name; private DynamicDoubleArray latList; private DynamicDoubleArray lonList; private DynamicDoubleArray altimList; private List<String> dateList; private boolean boundsAreDirty = true; private double minLat = 0.0; private double minLon = 0.0; private double maxLat = 0.0; private double maxLon = 0.0; private float width = 1f; private String color = "#ff0000ff"; //$NON-NLS-1$ /** * @param name line name. * @param lonList lon coords. * @param latList lat coords. * @param altimList elevation list. * @param dateList date list. */ public Line( String name, DynamicDoubleArray lonList, DynamicDoubleArray latList, DynamicDoubleArray altimList, List<String> dateList ) { this.name = name; this.lonList = lonList; this.latList = latList; this.altimList = altimList; this.dateList = dateList; } /** * Empty line constructor. * * @param logid log id. */ public Line( String logid ) { this.name = logid; this.lonList = new DynamicDoubleArray(); this.latList = new DynamicDoubleArray(); this.altimList = new DynamicDoubleArray(); this.dateList = new ArrayList<>(); } /** * @param lon lon * @param lat lat * @param altim elevation. * @param date date. */ public void addPoint( double lon, double lat, double altim, String date ) { if (lat < 0.0001 && lon < 0.0001) { // don't add points in 0,0 return; } boundsAreDirty = true; this.lonList.add(lon); this.latList.add(lat); this.altimList.add(altim); this.dateList.add(date); } /** * Set the style. * * @param width width. * @param color color. */ public void setStyle( float width, String color ) { if (width > 0) this.width = width; if (color != null) this.color = color; } /** * Set the name. * * @param name the name. */ public void setName( String name ) { this.name = name; } /** * @return line name. */ public String getName() { return name; } /** * @return lat list */ public DynamicDoubleArray getLatList() { return latList; } /** * @return lon list */ public DynamicDoubleArray getLonList() { return lonList; } /** * @return elevations list. */ public DynamicDoubleArray getAltimList() { return altimList; } /** * @return dates list. */ public List<String> getDateList() { return dateList; } /** * Calculates the length of a line. * * @return the length of the line in meters. */ public double getLength() { final float[] dist = new float[3]; double length = 0; for( int i = 0; i < latList.size() - 1; i++ ) { double lat1 = latList.get(i); double lon1 = lonList.get(i); double altim1 = altimList.get(i); double lat2 = latList.get(i + 1); double lon2 = lonList.get(i + 1); double altim2 = altimList.get(i + 1); Location.distanceBetween(lat1, lon1, lat2, lon2, dist); double deltaAltim = abs(altim2 - altim1); double deltaLength = sqrt(pow(deltaAltim, 2.0) + pow(dist[0], 2.0)); length = length + deltaLength; } return length; } @SuppressWarnings("nls") public String toKmlString() { String name = Utilities.makeXmlSafe(this.name); StringBuilder sB = new StringBuilder(); sB.append("<Placemark>\n"); sB.append("<name>" + name + "</name>\n"); sB.append("<visibility>1</visibility>\n"); sB.append("<LineString>\n"); sB.append("<tessellate>1</tessellate>\n"); sB.append("<coordinates>\n"); for( int i = 0; i < lonList.size(); i++ ) { double lon = lonList.get(i); double lat = latList.get(i); sB.append(lon).append(",").append(lat).append(",1 \n"); } sB.append("</coordinates>\n"); sB.append("</LineString>\n"); sB.append("<Style>\n"); sB.append("<LineStyle>\n"); int parsedColor = ColorUtilities.toColor(color); String hexColor = "#" + Integer.toHexString(parsedColor); sB.append("<color>").append(hexColor).append("</color>\n"); sB.append("<width>").append(width).append("</width>\n"); sB.append("</LineStyle>\n"); sB.append("</Style>\n"); sB.append("</Placemark>\n"); return sB.toString(); } public boolean hasImages() { return false; } @Override public List<String> getImageIds() { return Collections.emptyList(); } private void calculateBounds() { if (boundsAreDirty) { double[] latArray = latList.getInternalArray(); int size = latList.size(); minLat = Double.POSITIVE_INFINITY; maxLat = Double.NEGATIVE_INFINITY; for( int i = 0; i < size; i++ ) { double d = latArray[i]; minLat = Math.min(d, minLat); maxLat = Math.max(d, maxLat); } double[] lonArray = lonList.getInternalArray(); minLon = Double.POSITIVE_INFINITY; maxLon = Double.NEGATIVE_INFINITY; for( int i = 0; i < size; i++ ) { double d = lonArray[i]; minLon = Math.min(d, minLon); maxLon = Math.max(d, maxLon); } boundsAreDirty = false; } } public double getMinLat() { calculateBounds(); return minLat; } public double getMinLon() { calculateBounds(); return minLon; } public double getMaxLat() { calculateBounds(); return maxLat; } public double getMaxLon() { calculateBounds(); return maxLon; } @SuppressWarnings("nls") public String toGpxString() throws Exception { String name = Utilities.makeXmlSafe(this.name); StringBuilder sb = new StringBuilder(); sb.append(GpxUtilities.GPX_TRACK_START).append("\n"); sb.append(GpxUtilities.getTrackNameString(name)).append("\n"); sb.append(GpxUtilities.GPX_TRACKSEGMENT_START).append("\n"); int size = latList.size(); double[] latArray = latList.getInternalArray(); double[] lonArray = lonList.getInternalArray(); double[] altimArray = altimList.getInternalArray(); for( int i = 0; i < size; i++ ) { String dateString = dateList.get(i); long time = Long.parseLong(dateString); // TODO change this sooner or later - needs ts to be hold differently in db dateString = TimeUtilities.INSTANCE.TIME_FORMATTER_GPX_UTC.format(new Date(time)); String trackPointString = GpxUtilities.getTrackPointString(latArray[i], lonArray[i], altimArray[i], dateString); sb.append(trackPointString); } sb.append(GpxUtilities.GPX_TRACKSEGMENT_END).append("\n"); sb.append(GpxUtilities.GPX_TRACK_END).append("\n"); return sb.toString(); } }