All Downloads are FREE. Search and download functionalities are using the official Maven repository.

openlr.encoder.routesearch.RouteSearch Maven / Gradle / Ivy

Go to download

The encoder package holds the reference implementation for the OpenLR encoder. It takes a (map-dependent) location as input and generates a corresponding (map-agnostic) location reference. This package uses the OpenLR map package and the OpenLR data package.

The newest version!
/**
 * Licensed to the TomTom International B.V. under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  TomTom International B.V.
 * 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. *

* Copyright (C) 2009-2019 TomTom International B.V. *

* TomTom (Legal Department) * Email: [email protected] *

* TomTom (Technical contact) * Email: [email protected] *

* Address: TomTom International B.V., Oosterdoksstraat 114, 1011DK Amsterdam, * the Netherlands *

* Copyright (C) 2009-2019 TomTom International B.V. *

* TomTom (Legal Department) * Email: [email protected] *

* TomTom (Technical contact) * Email: [email protected] *

* Address: TomTom International B.V., Oosterdoksstraat 114, 1011DK Amsterdam, * the Netherlands */ /** * Copyright (C) 2009-2019 TomTom International B.V. * * TomTom (Legal Department) * Email: [email protected] * * TomTom (Technical contact) * Email: [email protected] * * Address: TomTom International B.V., Oosterdoksstraat 114, 1011DK Amsterdam, * the Netherlands */ package openlr.encoder.routesearch; import openlr.collection.OpenLongHashSet; import openlr.encoder.OpenLREncoderProcessingException; import openlr.encoder.OpenLREncoderProcessingException.EncoderProcessingError; import openlr.encoder.routesearch.RouteSearchResult.RouteSearchReturnCode; import openlr.map.FunctionalRoadClass; import openlr.map.FunctionalRoadClass.FrcComparator; import openlr.map.Line; import openlr.map.Node; import openlr.map.utils.GeometryUtils; import openlr.map.utils.PQElem; import openlr.map.utils.PathUtils; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * The Class RouteSearch defines a modified A* route search which checks * automatically if a provided location (= ordered and connected list of lines) * is also a shortest-path. The route search calculates a shortest-path between * the start and the destination of the location. It will be checked in every * iteration if the desired location is still part of the current shortest-path * tree. The route calculation will stop if this is not the case and it will * return one or two lines which can be used as intermediate information to * split the location into several shortest-paths. * *

* OpenLR is a trade mark of TomTom International B.V. *

* email: [email protected] * * @author TomTom International B.V. */ public class RouteSearch { /** The Constant FRC_COMPARATOR. */ private static final FrcComparator FRC_COMPARATOR = new FunctionalRoadClass.FrcComparator(); /** The logger */ private static final Logger LOG = Logger.getLogger(RouteSearch.class); /** The location. */ private final List location; /** The start line. */ private final Line startLine; /** The dest line. */ private final Line destLine; /** The start loop index. */ private final int startLoopIndex; /** The end loop index. */ private final int endLoopIndex; /** the x coordinate for the calculation of the heuristic value */ private double destX = 0; /** the y coordinate for the calculation of the heuristic value */ private double destY = 0; private int lengthBetweenStartAndEndLineAlongLocation = 0; /** * Instantiates a new route search. * * @param loc * the loc * @throws OpenLREncoderProcessingException * the open lr encoder runtime exception */ public RouteSearch(final List loc) throws OpenLREncoderProcessingException { location = loc; if (location == null || location.isEmpty()) { throw new OpenLREncoderProcessingException( EncoderProcessingError.ROUTE_CONSTRUCTION_ERROR); } startLine = location.get(0); destLine = location.get(location.size() - 1); for (int routeIndex = 0; routeIndex < location.size(); ++routeIndex) { lengthBetweenStartAndEndLineAlongLocation += location.get(routeIndex).getLineLength(); } startLoopIndex = checkLoopAtStart(); endLoopIndex = checkLoopAtEnd(); } /** * Check loop at start. * * @return the int */ private int checkLoopAtStart() { int index = location.subList(1, location.size()).indexOf( startLine); if (index > 0) { // loop detected int totalLoops = Collections.frequency(location, startLine); if (LOG.isDebugEnabled()) { LOG.debug("loop detected"); LOG.debug("total occurences of start line: " + totalLoops); } } return index; } /** * Check loop at end. * * @return the int */ private int checkLoopAtEnd() { int firstEndLineIndex = location.indexOf(destLine); int index = -1; if (firstEndLineIndex < location.size() - 1) { // loop detected if (LOG.isDebugEnabled()) { LOG.debug("end loop detected"); } index = firstEndLineIndex; } return index; } /** * Calculates a shortest-path between start and destination of the location * and stops if the provided location is not part of the shortest path tree * anymore. The returned route search result contains information about * lines which can be used as intermediates which are good lines to split * the location into several shortest-paths. It also contains information * about the shortest-path found (so far). * * @return the status of the route search after stopping the search * @throws OpenLREncoderProcessingException if route search fails */ public final RouteSearchResult calculateRoute() throws OpenLREncoderProcessingException { if (LOG.isDebugEnabled()) { LOG.debug("route search between start (" + startLine.getID() + ") and dest (" + destLine.getID() + ")"); } RouteSearchResult result = null; // start and end are equals but there is a path in between // so skip the start and proceed with the next line in the location if (startLine.getID() == destLine.getID() && location.size() > 1) { List route = new ArrayList(1); route.add(startLine); result = new RouteSearchResult( RouteSearchReturnCode.INTERMEDIATE_FOUND, route, location .get(1), 1); } else if (startLoopIndex == 0) { // there is a loop of a single line in the location List route = new ArrayList(); route.add(startLine); result = new RouteSearchResult(RouteSearchReturnCode.INTERMEDIATE_FOUND, route, location.get(1), 1); } else { //we have to start a search // global data structures IntermediateHandler iHandler = new IntermediateHandler(location); RouteSearchData data = new RouteSearchData(); // for the use of the heuristic Node e = destLine.getEndNode(); destX = e.getLongitudeDeg(); destY = e.getLatitudeDeg(); // initialize the open list with the start element int startLength = startLine.getLineLength(); PQElem startElem = new PQElem(startLine, 0/* HACK */, startLength, null); data.addToOpen(startElem); // open.add(startElem); // bestValues.put(startLine.getID(), startLength); OpenLongHashSet locationIDs = new OpenLongHashSet(location.size()); for (Line l : location) { locationIDs.put(l.getID()); } // main loop while (!data.isOpenEmpty()) { // stop if route or intermediate is found or if no further line // is // available // get the top element of the open list PQElem actualElement = data.pollElement(); // check the location being part of the shortest path tree and // if not change the state to INTERMEDIATE_FOUND if (locationIDs.containsKey(actualElement.getLine().getID())) { result = iHandler.checkIntermediate(actualElement, data); if (result != null) { break; } } // check if we have found the destination and if so then // construct the route and stop calculation if (actualElement.getLine().getID() == destLine.getID()) { if (endLoopIndex >= 0) { //route found until the end loop starts //break here and add intermediate List route = PathUtils .constructPath(actualElement.getPrevious()); result = new RouteSearchResult( RouteSearchReturnCode.INTERMEDIATE_FOUND, route, destLine, endLoopIndex); break; } else { List route = PathUtils .constructPath(actualElement); if (route.isEmpty()) { // strange error throw new OpenLREncoderProcessingException( EncoderProcessingError.ROUTE_CONSTRUCTION_ERROR); } else { // route found and constructed result = new RouteSearchResult( RouteSearchResult.RouteSearchReturnCode.ROUTE_FOUND, route); break; } } } //check for loops at start if (startLoopIndex > 0 && iHandler.getLastElemOnRoutePos() == startLoopIndex) { // the start loop is completed and route search needs to be // interrupted, add intermediate if (LOG.isDebugEnabled()) { LOG.debug("loop is traversed, intermediate found"); } List route = PathUtils.constructPath(actualElement.getPrevious()); result = new RouteSearchResult( RouteSearchReturnCode.INTERMEDIATE_FOUND, route, startLine, startLoopIndex); break; } //route search can continue so // iterate over the successors, because we have not reached the // end extractNextLines(actualElement, data); } if (result == null) { //no route found result = new RouteSearchResult(RouteSearchReturnCode.NO_ROUTE_FOUND); } } return result; } /** * Extract the successor lines and add the lines to the open list if a * shorter distance to that line is found. * * @param actualElement the current element * @param data the data * @param lfrc the lfrc */ private void extractNextLines(final PQElem actualElement, final RouteSearchData data) { Iterator iterNext = actualElement.getLine() .getNextLines(); // check all successors while (iterNext.hasNext()) { Line succ = iterNext.next(); // calculate heuristic value, length, weighted length Node succEnd = succ.getEndNode(); int heurist = (int) Math.round(GeometryUtils.distance(destX, destY, succEnd.getLongitudeDeg(), succEnd.getLatitudeDeg())); int newDist = actualElement.getSecondVal() + succ.getLineLength(); int newHeurVal = newDist + heurist; //Length filter if (newDist > lengthBetweenStartAndEndLineAlongLocation) { continue; } // check if we already have a value for this line if (data.hasLengthValue(succ)) { // check if we can improve the value if (newDist < data.getLengthValue(succ)) { // improving the value means deleting the existing // entry and creating a new one with the better // values PQElem newElem = new PQElem(succ, newHeurVal, newDist, actualElement); data.updateInOpen(newElem); } } else { // no value stored yet, so create a new one PQElem newElem = new PQElem(succ, newHeurVal, newDist, actualElement); data.addToOpen(newElem); } } } /** * {@inheritDoc} */ @Override public final String toString() { StringBuilder sb = new StringBuilder(); sb.append(" destination lon: ").append(destX); sb.append(" destination lat: ").append(destY); if (startLoopIndex > 0) { sb.append(" start loop found at: ").append(startLoopIndex); } if (endLoopIndex > 0) { sb.append(" end loop found at: ").append(endLoopIndex); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy