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