/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 org.opentripplanner.routing.impl; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.opentripplanner.routing.edgetype.StreetEdge; import org.opentripplanner.routing.edgetype.StreetTraversalPermission; import org.opentripplanner.routing.vertextype.StreetVertex; public class CandidateEdgeBundle extends ArrayList<CandidateEdge> { private static final long serialVersionUID = 20120222L; // maximum difference in distance for two geometries to be considered coincident public static final double DISTANCE_ERROR = 0.000001; private static final double DIRECTION_ERROR = 0.05; public StreetVertex endwiseVertex = null; public CandidateEdge best = null; public boolean add(CandidateEdge ce) { if (best == null || ce.score < best.score) { endwiseVertex = ce.getEndwiseVertex(); best = ce; } return super.add(ce); } public List<StreetEdge> toEdgeList() { List<StreetEdge> ret = new ArrayList<StreetEdge>(); for (CandidateEdge ce : this) { ret.add(ce.getEdge()); } return ret; } static class DistanceAndAngle { double distance; double angle; boolean endwise; public DistanceAndAngle(double distance, double angle, boolean endwise) { this.distance = distance; this.angle = angle; this.endwise = endwise; } } public Collection<CandidateEdgeBundle> binByDistanceAndAngle() { // Map of from distance, angle pairs to bundles of edges. Map<DistanceAndAngle, CandidateEdgeBundle> bins = new HashMap<DistanceAndAngle, CandidateEdgeBundle>(); CANDIDATE: for (CandidateEdge ce : this) { for (Entry<DistanceAndAngle, CandidateEdgeBundle> bin : bins.entrySet()) { double distance = bin.getKey().distance; double direction = bin.getKey().angle; if (Math.abs(direction - ce.getDirectionToEdge()) < DIRECTION_ERROR && Math.abs(distance - ce.distance) < DISTANCE_ERROR && ce.endwise() == bin.getKey().endwise) { bin.getValue().add(ce); continue CANDIDATE; } } DistanceAndAngle rTheta = new DistanceAndAngle(ce.distance, ce.getDirectionToEdge(), ce.endwise()); CandidateEdgeBundle bundle = new CandidateEdgeBundle(); bundle.add(ce); bins.put(rTheta, bundle); } return bins.values(); } public boolean endwise() { return endwiseVertex != null; } public double getScore() { return best.score; } public boolean isPlatform() { for (CandidateEdge ce : CandidateEdgeBundle.this) { StreetEdge e = ce.getEdge(); if ((e.getStreetClass() & StreetEdge.ANY_PLATFORM_MASK) != 0) { return true; } } return false; } public boolean allowsCars() { for (CandidateEdge ce : CandidateEdgeBundle.this) { StreetEdge e = ce.getEdge(); if (e.getPermission().allows(StreetTraversalPermission.CAR)) { return true; } } return false; } }