Java tutorial
/* * Copyright (C) 2014 team-cachebox.de * * Licensed under the : GNU General Public License (GPL); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/gpl.html * * 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 CB_UI; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import org.slf4j.LoggerFactory; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.math.Vector2; import CB_Locator.CoordinateGPS; import CB_Locator.Map.Descriptor; import CB_Locator.Map.MapTileLoader; import CB_Locator.Map.PolylineReduction; import CB_Locator.Map.Track; import CB_Locator.Map.TrackPoint; import CB_UI.GL_UI.Views.MapView; import CB_UI_Base.GL_UI.DrawUtils; import CB_UI_Base.GL_UI.Sprites; import CB_UI_Base.GL_UI.GL_Listener.GL; import CB_UI_Base.Math.CB_RectF; import CB_UI_Base.Math.UI_Size_Base; import CB_Utils.MathUtils; import CB_Utils.MathUtils.CalculationType; import CB_Utils.Log.Log; import CB_Utils.Util.FileIO; import CB_Utils.Util.HSV_Color; import CB_Utils.fileProvider.File; import CB_Utils.fileProvider.FileFactory; public class RouteOverlay { final static org.slf4j.Logger log = LoggerFactory.getLogger(RouteOverlay.class); /** * ist in Routes eine von openRouteService generierter Track enthalten, dann enthlt diese Variable diesen track. */ private static Track OpenRoute; private static ArrayList<Track> Routes = new ArrayList<Track>(); public static boolean mRoutesChanged = false; public static Color getNextColor() { Color ret = ColorField[(Routes.size()) % ColorField.length]; if (ret == null) initialColorField(); return ColorField[(Routes.size()) % ColorField.length]; } private static Color[] ColorField = new Color[13]; private static void initialColorField() { ColorField[0] = Color.RED; ColorField[1] = Color.YELLOW; ColorField[2] = Color.BLACK; ColorField[3] = Color.LIGHT_GRAY; ColorField[4] = Color.GREEN; ColorField[5] = Color.BLUE; ColorField[6] = Color.CYAN; ColorField[7] = Color.GRAY; ColorField[8] = Color.MAGENTA; ColorField[9] = Color.ORANGE; ColorField[10] = Color.DARK_GRAY; ColorField[11] = Color.PINK; ColorField[12] = Color.WHITE; } public static void RoutesChanged() { mRoutesChanged = true; GL.that.renderOnce(); } // Read track from gpx file // attention it is possible that a gpx file contains more than 1 <trk> segments public static Track MultiLoadRoute(String file, Color color) { float[] dist = new float[4]; double Distance = 0; double AltitudeDifference = 0; double DeltaAltitude = 0; CoordinateGPS FromPosition = new CoordinateGPS(0, 0); BufferedReader reader; try { InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF8"); reader = new BufferedReader(isr); Track route = new Track(null, color); String line = null; String tmpLine = null; String GPXName = null; boolean isSeg = false; boolean isTrk = false; boolean isRte = false; boolean IStrkptORrtept = false; boolean ReadName = false; int AnzTracks = 0; CoordinateGPS lastAcceptedCoordinate = null; double lastAcceptedDirection = -1; Date lastAcceptedTime = null; StringBuilder sb = new StringBuilder(); String rline = null; while ((rline = reader.readLine()) != null) { for (int i = 0; i < rline.length(); i++) { char nextChar = rline.charAt(i); sb.append(nextChar); if (nextChar == '>') { line = sb.toString().trim().toLowerCase(); tmpLine = sb.toString(); sb = new StringBuilder(); if (!isTrk) // Begin of the Track detected? { if (line.indexOf("<trk>") > -1) { isTrk = true; continue; } } if (!isSeg) // Begin of the Track Segment detected? { if (line.indexOf("<trkseg>") > -1) { isSeg = true; route = new Track(null, color); route.FileName = file; Distance = 0; AltitudeDifference = 0; AnzTracks++; if (GPXName == null) route.Name = FileIO.GetFileName(file); else { if (AnzTracks <= 1) route.Name = GPXName; else route.Name = GPXName + AnzTracks; } continue; } } if (!isRte) // Begin of the Route detected? { if (line.indexOf("<rte>") > -1) { isRte = true; route = new Track(null, color); route.FileName = file; Distance = 0; AltitudeDifference = 0; AnzTracks++; if (GPXName != null) route.Name = FileIO.GetFileName(file); else { if (AnzTracks <= 1) route.Name = GPXName; else route.Name = GPXName + AnzTracks; } continue; } } if ((line.indexOf("<name>") > -1) & !IStrkptORrtept) // found <name>? { ReadName = true; continue; } if (ReadName & !IStrkptORrtept) { int cdata_start = 0; int name_start = 0; int name_end; name_end = line.indexOf("</name>"); // Name contains cdata? cdata_start = line.indexOf("[cdata["); if (cdata_start > -1) { name_start = cdata_start + 7; name_end = line.indexOf("]"); } if (name_end > name_start) { // tmpLine, damit Gro-/Kleinschreibung beachtet wird if (isSeg | isRte) route.Name = tmpLine.substring(name_start, name_end); else GPXName = tmpLine.substring(name_start, name_end); } ReadName = false; continue; } if (line.indexOf("</trkseg>") > -1) // End of the Track Segment detected? { if (route.Points.size() < 2) route.Name = "no Route segment found"; route.ShowRoute = true; route.TrackLength = Distance; route.AltitudeDifference = AltitudeDifference; add(route); isSeg = false; break; } if (line.indexOf("</rte>") > -1) // End of the Route detected? { if (route.Points.size() < 2) route.Name = "no Route segment found"; route.ShowRoute = true; route.TrackLength = Distance; route.AltitudeDifference = AltitudeDifference; add(route); isRte = false; break; } if ((line.indexOf("<trkpt") > -1) | (line.indexOf("<rtept") > -1)) { IStrkptORrtept = true; // Trackpoint lesen int lonIdx = line.indexOf("lon=\"") + 5; int latIdx = line.indexOf("lat=\"") + 5; int lonEndIdx = line.indexOf("\"", lonIdx); int latEndIdx = line.indexOf("\"", latIdx); String latStr = line.substring(latIdx, latEndIdx); String lonStr = line.substring(lonIdx, lonEndIdx); double lat = Double.valueOf(latStr); double lon = Double.valueOf(lonStr); lastAcceptedCoordinate = new CoordinateGPS(lat, lon); } if (line.indexOf("</time>") > -1) { // Time lesen int timIdx = line.indexOf("<time>") + 6; if (timIdx == 5) timIdx = 0; int timEndIdx = line.indexOf("</time>", timIdx); String timStr = line.substring(timIdx, timEndIdx); lastAcceptedTime = parseDate(timStr); } if (line.indexOf("</course>") > -1) { // Course lesen int couIdx = line.indexOf("<course>") + 8; if (couIdx == 7) couIdx = 0; int couEndIdx = line.indexOf("</course>", couIdx); String couStr = line.substring(couIdx, couEndIdx); lastAcceptedDirection = Double.valueOf(couStr); } if ((line.indexOf("</ele>") > -1) & IStrkptORrtept) { // Elevation lesen int couIdx = line.indexOf("<ele>") + 5; if (couIdx == 4) couIdx = 0; int couEndIdx = line.indexOf("</ele>", couIdx); String couStr = line.substring(couIdx, couEndIdx); lastAcceptedCoordinate.setElevation(Double.valueOf(couStr)); } if (line.indexOf("</gpxx:colorrgb>") > -1) { // Color lesen int couIdx = line.indexOf("<gpxx:colorrgb>") + 15; if (couIdx == 14) couIdx = 0; int couEndIdx = line.indexOf("</gpxx:colorrgb>", couIdx); String couStr = line.substring(couIdx, couEndIdx); color = new HSV_Color(couStr); route.setColor(color); } if ((line.indexOf("</trkpt>") > -1) | (line.indexOf("</rtept>") > -1) | ((line.indexOf("/>") > -1) & IStrkptORrtept)) { // trkpt abgeschlossen, jetzt kann der Trackpunkt erzeugt werden IStrkptORrtept = false; route.Points.add(new TrackPoint(lastAcceptedCoordinate.getLongitude(), lastAcceptedCoordinate.getLatitude(), lastAcceptedCoordinate.getElevation(), lastAcceptedDirection, lastAcceptedTime)); // Calculate the length of a Track if (!FromPosition.isValid()) { FromPosition = new CoordinateGPS(lastAcceptedCoordinate); FromPosition.setElevation(lastAcceptedCoordinate.getElevation()); FromPosition.setValid(true); } else { MathUtils.computeDistanceAndBearing(CalculationType.ACCURATE, FromPosition.getLatitude(), FromPosition.getLongitude(), lastAcceptedCoordinate.getLatitude(), lastAcceptedCoordinate.getLongitude(), dist); Distance += dist[0]; DeltaAltitude = Math .abs(FromPosition.getElevation() - lastAcceptedCoordinate.getElevation()); FromPosition = new CoordinateGPS(lastAcceptedCoordinate); if (DeltaAltitude >= 25.0) // nur aufaddieren wenn Hhenunterschied grer 10 Meter { FromPosition.setElevation(lastAcceptedCoordinate.getElevation()); AltitudeDifference = AltitudeDifference + DeltaAltitude; } } } } } } reader.close(); return route; } catch (FileNotFoundException e) { e.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } } /** * Going to assume date is always in the form:<br> * 2006-05-25T08:55:01Z<br> * 2006-05-25T08:56:35Z<br> * <br> * i.e.: yyyy-mm-ddThh-mm-ssZ <br> * code from Tommi Laukkanen http://www.substanceofcode.com * * @param dateString * @return */ private static Date parseDate(String dateString) { try { final int year = Integer.parseInt(dateString.substring(0, 4)); final int month = Integer.parseInt(dateString.substring(5, 7)); final int day = Integer.parseInt(dateString.substring(8, 10)); final int hour = Integer.parseInt(dateString.substring(11, 13)); final int minute = Integer.parseInt(dateString.substring(14, 16)); final int second = Integer.parseInt(dateString.substring(17, 19)); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month - 1); // Beware MONTH was counted for 0 to 11, so we have to subtract 1 calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); return calendar.getTime(); } catch (Exception e) { Log.err(log, "RouteOverlay", "Exception caught trying to parse date : ", e); } return null; } // Debug // public static int AllTrackPoints = 0; // public static int ReduceTrackPoints = 0; // public static int DrawedLineCount = 0; public static double Tolleranz = 0; public static int aktCalcedZoomLevel = -1; public class Route { private boolean mIsOpenRoute = false; private final Color mColor; protected ArrayList<TrackPoint> Points; Sprite ArrowSprite; Sprite PointSprite; float overlap = 0.9f; public Route(Color color) { mColor = color; Points = new ArrayList<TrackPoint>(); ArrowSprite = Sprites.Arrows.get(5); PointSprite = Sprites.Arrows.get(10); overlap = 0.9f; } public Route(Color color, boolean isOpenRoute) { mIsOpenRoute = isOpenRoute; if (isOpenRoute) { ArrowSprite = new Sprite(Sprites.Arrows.get(5)); PointSprite = new Sprite(Sprites.Arrows.get(10)); ArrowSprite.scale(1.6f); PointSprite.scale(0.2f); overlap = 1.9f; } else { ArrowSprite = Sprites.Arrows.get(5); PointSprite = Sprites.Arrows.get(10); overlap = 0.9f; } mColor = color; Points = new ArrayList<TrackPoint>(); } public boolean isOpenRoute() { return mIsOpenRoute; } } private static ArrayList<Route> DrawRoutes; public static void RenderRoute(Batch batch, MapView mapView) { int Zoom = mapView.getAktZoom(); float yVersatz = mapView.ySpeedVersatz; if (aktCalcedZoomLevel != Zoom || mRoutesChanged) {// Zoom or Routes changed => calculate new Sprite Points // Log.debug(log, "Zoom Changed => Calc Track Points"); mRoutesChanged = false; aktCalcedZoomLevel = Zoom; if (DrawRoutes == null) DrawRoutes = new ArrayList<RouteOverlay.Route>(); else DrawRoutes.clear(); double tolerance = 0.01 * Math.exp(-1 * (Zoom - 11)); Tolleranz = tolerance; for (int i = 0; i < Routes.size(); i++) { if (Routes.get(i) != null && Routes.get(i).ShowRoute) { addToDrawRoutes(tolerance, Routes.get(i), Zoom, false); } } if (GlobalCore.AktuelleRoute != null && GlobalCore.AktuelleRoute.ShowRoute) { addToDrawRoutes(tolerance, GlobalCore.AktuelleRoute, Zoom, false); } } // DrawedLineCount = 0; if (DrawRoutes != null && DrawRoutes.size() > 0) { for (Route rt : DrawRoutes) { Sprite ArrowSprite = rt.ArrowSprite; Sprite PointSprite = rt.PointSprite; float overlap = rt.overlap; ArrowSprite.setColor(rt.mColor); PointSprite.setColor(rt.mColor); float scale = UI_Size_Base.that.getScale(); for (int ii = 0; ii < rt.Points.size() - 1; ii++) { double MapX1 = 256.0 * Descriptor.LongitudeToTileX(MapTileLoader.MAX_MAP_ZOOM, rt.Points.get(ii).X); double MapY1 = -256.0 * Descriptor.LatitudeToTileY(MapTileLoader.MAX_MAP_ZOOM, rt.Points.get(ii).Y); double MapX2 = 256.0 * Descriptor.LongitudeToTileX(MapTileLoader.MAX_MAP_ZOOM, rt.Points.get(ii + 1).X); double MapY2 = -256.0 * Descriptor.LatitudeToTileY(MapTileLoader.MAX_MAP_ZOOM, rt.Points.get(ii + 1).Y); Vector2 screen1 = mapView.worldToScreen(new Vector2((float) MapX1, (float) MapY1)); Vector2 screen2 = mapView.worldToScreen(new Vector2((float) MapX2, (float) MapY2)); screen1.y -= yVersatz; screen2.y -= yVersatz; CB_RectF chkRec = new CB_RectF(mapView); chkRec.setPos(0, 0); // chk if line on Screen if (chkRec.contains(screen1.x, screen1.y) || chkRec.contains(screen2.x, screen2.y)) { DrawUtils.drawSpriteLine(batch, ArrowSprite, PointSprite, overlap * scale, screen1.x, screen1.y, screen2.x, screen2.y); // DrawedLineCount++; } else {// chk if intersection if (chkRec.getIntersection(screen1, screen2, 2) != null) { DrawUtils.drawSpriteLine(batch, ArrowSprite, PointSprite, overlap * scale, screen1.x, screen1.y, screen2.x, screen2.y); // DrawedLineCount++; } // the line is not on the screen } } } } } private static void addToDrawRoutes(double tolerance, Track track, int Zoom, boolean dontReduce) { synchronized (track.Points) { ArrayList<TrackPoint> reducedPoints; // ab zoom level 18 keine Punkte Reduzieren if (dontReduce || Zoom >= 18) { reducedPoints = track.Points; } else { reducedPoints = PolylineReduction.DouglasPeuckerReduction(track.Points, tolerance); } // AllTrackPoints = track.Points.size(); // ReduceTrackPoints = reducedPoints.size(); boolean isOpenRoute = track == OpenRoute; Route tmp = (new RouteOverlay()).new Route(track.mColor, isOpenRoute); tmp.Points = reducedPoints; DrawRoutes.add(tmp); } } public static void SaveRoute(String Path, Track track) { FileWriter writer = null; File gpxfile = FileFactory.createFile(Path); try { writer = gpxfile.getFileWriter(); try { writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); writer.append( "<gpx version=\"1.0\" creator=\"cachebox track recorder\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); Date now = new Date(); SimpleDateFormat datFormat = new SimpleDateFormat("yyyy-MM-dd"); String sDate = datFormat.format(now); datFormat = new SimpleDateFormat("HH:mm:ss"); sDate += "T" + datFormat.format(now) + "Z"; writer.append("<time>" + sDate + "</time>\n"); writer.append("<bounds minlat=\"-90\" minlon=\"-180\" maxlat=\"90\" maxlon=\"180\"/>\n"); writer.append("<trk>\n"); writer.append("<name>" + track.Name + "</name>\n"); writer.append("<extensions>\n<gpxx:TrackExtension>\n"); writer.append("<gpxx:ColorRGB>" + track.mColor.toString() + "</gpxx:ColorRGB>\n"); writer.append("</gpxx:TrackExtension>\n</extensions>\n"); writer.append("<trkseg>\n"); writer.flush(); } catch (IOException e) { Log.err(log, "SaveTrack", e); } } catch (IOException e1) { Log.err(log, "SaveTrack", e1); } try { for (int i = 0; i < track.Points.size(); i++) { writer.append("<trkpt lat=\"" + String.valueOf(track.Points.get(i).Y) + "\" lon=\"" + String.valueOf(track.Points.get(i).X) + "\">\n"); writer.append( " <ele>" + String.valueOf(String.valueOf(track.Points.get(i).Elevation)) + "</ele>\n"); SimpleDateFormat datFormat = new SimpleDateFormat("yyyy-MM-dd"); String sDate = datFormat.format(track.Points.get(i).TimeStamp); datFormat = new SimpleDateFormat("HH:mm:ss"); sDate += "T" + datFormat.format(track.Points.get(i).TimeStamp) + "Z"; writer.append(" <time>" + sDate + "</time>\n"); writer.append("</trkpt>\n"); } writer.append("</trkseg>\n"); writer.append("</trk>\n"); writer.append("</gpx>\n"); writer.flush(); writer.close(); } catch (IOException e) { Log.err(log, "SaveTrack", e); } writer = null; } public void LoadTrack(String trackPath) { LoadTrack(trackPath, ""); } public static void LoadTrack(String trackPath, String file) { String absolutPath = ""; if (file.equals("")) { absolutPath = trackPath; } else { absolutPath = trackPath + "/" + file; } MultiLoadRoute(absolutPath, getNextColor()); } public static void remove(Track route) { if (route == OpenRoute) { OpenRoute = null; } Routes.remove(route); RoutesChanged(); } /** * Dont use this for OpenRoute Track!! Use addOpenRoute(Track route) * * @param route */ public static void add(Track route) { Routes.add(route); RoutesChanged(); } public static void addOpenRoute(Track route) { if (OpenRoute == null) { route.setColor(new Color(0.85f, 0.1f, 0.2f, 1f)); Routes.add(0, route); OpenRoute = route; } else { // erst die alte route lschen Routes.remove(OpenRoute); route.setColor(OpenRoute.getColor()); Routes.add(0, route); OpenRoute = route; } RoutesChanged(); } public static int getRouteCount() { return Routes.size(); } public static Track getRoute(int position) { return Routes.get(position); } }