001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.gpx; 003 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.Collections; 007import java.util.List; 008import java.util.Objects; 009 010import org.openstreetmap.josm.data.Bounds; 011 012/** 013 * A gpx track segment consisting of multiple waypoints. 014 * @since 15496 015 */ 016public class GpxTrackSegment extends WithAttributes implements IGpxTrackSegment { 017 018 private final List<WayPoint> wayPoints; 019 private final Bounds bounds; 020 private final double length; 021 022 /** 023 * Constructs a new {@code GpxTrackSegment}. 024 * @param wayPoints list of waypoints 025 */ 026 public GpxTrackSegment(Collection<WayPoint> wayPoints) { 027 this.wayPoints = Collections.unmodifiableList(new ArrayList<>(wayPoints)); 028 this.bounds = calculateBounds(); 029 this.length = calculateLength(); 030 } 031 032 private Bounds calculateBounds() { 033 Bounds result = null; 034 for (WayPoint wpt: wayPoints) { 035 if (result == null) { 036 result = new Bounds(wpt.getCoor()); 037 } else { 038 result.extend(wpt.getCoor()); 039 } 040 } 041 return result; 042 } 043 044 private double calculateLength() { 045 double result = 0.0; // in meters 046 WayPoint last = null; 047 for (WayPoint tpt : wayPoints) { 048 if (last != null) { 049 Double d = last.getCoor().greatCircleDistance(tpt.getCoor()); 050 if (!d.isNaN() && !d.isInfinite()) { 051 result += d; 052 } 053 } 054 last = tpt; 055 } 056 return result; 057 } 058 059 @Override 060 public Bounds getBounds() { 061 return bounds == null ? null : new Bounds(bounds); 062 } 063 064 @Override 065 public Collection<WayPoint> getWayPoints() { 066 return Collections.unmodifiableList(wayPoints); 067 } 068 069 @Override 070 public double length() { 071 return length; 072 } 073 074 @Override 075 public int getUpdateCount() { 076 return 0; 077 } 078 079 @Override 080 public int hashCode() { 081 return Objects.hash(super.hashCode(), wayPoints); 082 } 083 084 @Override 085 public boolean equals(Object obj) { 086 if (this == obj) 087 return true; 088 if (obj == null) 089 return false; 090 if (!super.equals(obj)) 091 return false; 092 if (getClass() != obj.getClass()) 093 return false; 094 GpxTrackSegment other = (GpxTrackSegment) obj; 095 if (wayPoints == null) { 096 if (other.wayPoints != null) 097 return false; 098 } else if (!wayPoints.equals(other.wayPoints)) 099 return false; 100 return true; 101 } 102}