/* * Licensed to GraphHopper GmbH under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * GraphHopper GmbH licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 com.graphhopper.util; import com.graphhopper.PathWrapper; import com.graphhopper.routing.Path; import com.graphhopper.util.exceptions.ConnectionNotFoundException; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * This class merges a list of points into one point recognizing the specified places. * <p> * * @author Peter Karich * @author ratrun */ public class PathMerger { private static final DouglasPeucker DP = new DouglasPeucker(); private boolean enableInstructions = true; private boolean simplifyResponse = true; private DouglasPeucker douglasPeucker = DP; private boolean calcPoints = true; public PathMerger setCalcPoints(boolean calcPoints) { this.calcPoints = calcPoints; return this; } public PathMerger setDouglasPeucker(DouglasPeucker douglasPeucker) { this.douglasPeucker = douglasPeucker; return this; } public PathMerger setSimplifyResponse(boolean simplifyRes) { this.simplifyResponse = simplifyRes; return this; } public PathMerger setEnableInstructions(boolean enableInstructions) { this.enableInstructions = enableInstructions; return this; } public void doWork(PathWrapper altRsp, List<Path> paths, Translation tr) { int origPoints = 0; long fullTimeInMillis = 0; double fullWeight = 0; double fullDistance = 0; boolean allFound = true; InstructionList fullInstructions = new InstructionList(tr); PointList fullPoints = PointList.EMPTY; List<String> description = new ArrayList<String>(); for (int pathIndex = 0; pathIndex < paths.size(); pathIndex++) { Path path = paths.get(pathIndex); description.addAll(path.getDescription()); fullTimeInMillis += path.getTime(); fullDistance += path.getDistance(); fullWeight += path.getWeight(); if (enableInstructions) { InstructionList il = path.calcInstructions(tr); if (!il.isEmpty()) { if (fullPoints.isEmpty()) { PointList pl = il.get(0).getPoints(); // do a wild guess about the total number of points to avoid reallocation a bit fullPoints = new PointList(il.size() * Math.min(10, pl.size()), pl.is3D()); } for (Instruction i : il) { if (simplifyResponse) { origPoints += i.getPoints().size(); douglasPeucker.simplify(i.getPoints()); } fullInstructions.add(i); fullPoints.add(i.getPoints()); } // if not yet reached finish replace with 'reached via' if (pathIndex + 1 < paths.size()) { ViaInstruction newInstr = new ViaInstruction(fullInstructions.get(fullInstructions.size() - 1)); newInstr.setViaCount(pathIndex + 1); fullInstructions.replaceLast(newInstr); } } } else if (calcPoints) { PointList tmpPoints = path.calcPoints(); if (fullPoints.isEmpty()) fullPoints = new PointList(tmpPoints.size(), tmpPoints.is3D()); if (simplifyResponse) { origPoints = tmpPoints.getSize(); douglasPeucker.simplify(tmpPoints); } fullPoints.add(tmpPoints); } allFound = allFound && path.isFound(); } if (!fullPoints.isEmpty()) { String debug = altRsp.getDebugInfo() + ", simplify (" + origPoints + "->" + fullPoints.getSize() + ")"; altRsp.addDebugInfo(debug); if (fullPoints.is3D) calcAscendDescend(altRsp, fullPoints); } if (enableInstructions) altRsp.setInstructions(fullInstructions); if (!allFound) altRsp.addError(new ConnectionNotFoundException("Connection between locations not found", Collections.<String, Object>emptyMap())); altRsp.setDescription(description). setPoints(fullPoints). setRouteWeight(fullWeight). setDistance(fullDistance). setTime(fullTimeInMillis); } private void calcAscendDescend(final PathWrapper rsp, final PointList pointList) { double ascendMeters = 0; double descendMeters = 0; double lastEle = pointList.getElevation(0); for (int i = 1; i < pointList.size(); ++i) { double ele = pointList.getElevation(i); double diff = Math.abs(ele - lastEle); if (ele > lastEle) ascendMeters += diff; else descendMeters += diff; lastEle = ele; } rsp.setAscend(ascendMeters); rsp.setDescend(descendMeters); } }