Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.reader.osm;
import com.carrotsearch.hppc.IntIntMap;
import com.carrotsearch.hppc.LongArrayList;
import com.carrotsearch.hppc.LongHashSet;
import com.carrotsearch.hppc.LongSet;
import com.carrotsearch.hppc.cursors.LongCursor;
import com.graphhopper.coll.GHLongLongHashMap;
import com.graphhopper.reader.ReaderElement;
import com.graphhopper.reader.ReaderNode;
import com.graphhopper.reader.ReaderRelation;
import com.graphhopper.reader.ReaderWay;
import com.graphhopper.reader.dem.EdgeElevationSmoothingMovingAverage;
import com.graphhopper.reader.dem.EdgeElevationSmoothingRamer;
import com.graphhopper.reader.dem.EdgeSampling;
import com.graphhopper.reader.dem.ElevationProvider;
import com.graphhopper.routing.OSMReaderConfig;
import com.graphhopper.routing.ev.Country;
import com.graphhopper.routing.ev.EdgeIntAccess;
import com.graphhopper.routing.ev.State;
import com.graphhopper.routing.util.AreaIndex;
import com.graphhopper.routing.util.CustomArea;
import com.graphhopper.routing.util.FerrySpeedCalculator;
import com.graphhopper.routing.util.OSMParsers;
import com.graphhopper.routing.util.countryrules.CountryRule;
import com.graphhopper.routing.util.countryrules.CountryRuleFactory;
import com.graphhopper.routing.util.parsers.RestrictionSetter;
import com.graphhopper.search.KVStorage;
import com.graphhopper.storage.BaseGraph;
import com.graphhopper.storage.IntsRef;
import com.graphhopper.storage.NodeAccess;
import com.graphhopper.storage.TurnCostStorage;
import com.graphhopper.util.*;
import com.graphhopper.util.shapes.GHPoint;
import com.graphhopper.util.shapes.GHPoint3D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.LongToIntFunction;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.graphhopper.search.KVStorage.KeyValue.*;
import static com.graphhopper.util.GHUtility.OSM_WARNING_LOGGER;
import static com.graphhopper.util.Helper.nf;
import static java.util.Collections.emptyList;
/**
* Parses an OSM file (xml, zipped xml or pbf) and creates a graph from it. The OSM file is actually read twice.
* During the first scan we determine the 'type' of each node, i.e. we check whether a node only appears in a single way
* or represents an intersection of multiple ways, or connects two ways. We also scan the relations and store them for
* each way ID in memory.
* During the second scan we store the coordinates of the nodes that belong to ways in memory and then split each way
* into several segments that are divided by intersections or barrier nodes. Each segment is added as an edge of the
* resulting graph. Afterwards we scan the relations again to determine turn restrictions.
**/
public class OSMReader {
private static final Logger LOGGER = LoggerFactory.getLogger(OSMReader.class);
private static final Pattern WAY_NAME_PATTERN = Pattern.compile("; *");
private final OSMReaderConfig config;
private final BaseGraph baseGraph;
private final EdgeIntAccess edgeIntAccess;
private final NodeAccess nodeAccess;
private final TurnCostStorage turnCostStorage;
private final OSMParsers osmParsers;
private final DistanceCalc distCalc = DistanceCalcEarth.DIST_EARTH;
private final RestrictionSetter restrictionSetter;
private ElevationProvider eleProvider = ElevationProvider.NOOP;
private AreaIndex areaIndex;
private CountryRuleFactory countryRuleFactory = null;
private File osmFile;
private final RamerDouglasPeucker simplifyAlgo = new RamerDouglasPeucker();
private final IntsRef tempRelFlags;
private Date osmDataDate;
private long zeroCounter = 0;
private GHLongLongHashMap osmWayIdToRelationFlagsMap = new GHLongLongHashMap(200, .5f);
private WayToEdgesMap restrictedWaysToEdgesMap = new WayToEdgesMap();
private List restrictionRelations = new ArrayList<>();
public OSMReader(BaseGraph baseGraph, OSMParsers osmParsers, OSMReaderConfig config) {
this.baseGraph = baseGraph;
this.edgeIntAccess = baseGraph.createEdgeIntAccess();
this.config = config;
this.nodeAccess = baseGraph.getNodeAccess();
this.osmParsers = osmParsers;
this.restrictionSetter = new RestrictionSetter(baseGraph);
simplifyAlgo.setMaxDistance(config.getMaxWayPointDistance());
simplifyAlgo.setElevationMaxDistance(config.getElevationMaxWayPointDistance());
turnCostStorage = baseGraph.getTurnCostStorage();
tempRelFlags = osmParsers.createRelationFlags();
if (tempRelFlags.length != 2)
// we use a long to store relation flags currently, so the relation flags ints ref must have length 2
throw new IllegalArgumentException("OSMReader cannot use relation flags with != 2 integers");
}
/**
* Sets the OSM file to be read. Supported formats include .osm.xml, .osm.gz and .xml.pbf
*/
public OSMReader setFile(File osmFile) {
this.osmFile = osmFile;
return this;
}
/**
* The area index is queried for each OSM way and the associated areas are added to the way's tags
*/
public OSMReader setAreaIndex(AreaIndex areaIndex) {
this.areaIndex = areaIndex;
return this;
}
public OSMReader setElevationProvider(ElevationProvider eleProvider) {
if (eleProvider == null)
throw new IllegalStateException("Use the NOOP elevation provider instead of null or don't call setElevationProvider");
if (!nodeAccess.is3D() && ElevationProvider.NOOP != eleProvider)
throw new IllegalStateException("Make sure you graph accepts 3D data");
this.eleProvider = eleProvider;
return this;
}
public OSMReader setCountryRuleFactory(CountryRuleFactory countryRuleFactory) {
this.countryRuleFactory = countryRuleFactory;
return this;
}
public void readGraph() throws IOException {
if (osmParsers == null)
throw new IllegalStateException("Tag parsers were not set.");
if (osmFile == null)
throw new IllegalStateException("No OSM file specified");
if (!osmFile.exists())
throw new IllegalStateException("Your specified OSM file does not exist:" + osmFile.getAbsolutePath());
if (!baseGraph.isInitialized())
throw new IllegalStateException("BaseGraph must be initialize before we can read OSM");
WaySegmentParser waySegmentParser = new WaySegmentParser.Builder(baseGraph.getNodeAccess(), baseGraph.getDirectory())
.setElevationProvider(eleProvider)
.setWayFilter(this::acceptWay)
.setSplitNodeFilter(this::isBarrierNode)
.setWayPreprocessor(this::preprocessWay)
.setRelationPreprocessor(this::preprocessRelations)
.setRelationProcessor(this::processRelation)
.setEdgeHandler(this::addEdge)
.setWorkerThreads(config.getWorkerThreads())
.build();
waySegmentParser.readOSM(osmFile);
osmDataDate = waySegmentParser.getTimeStamp();
if (baseGraph.getNodes() == 0)
throw new RuntimeException("Graph after reading OSM must not be empty");
releaseEverythingExceptRestrictionData();
addRestrictionsToGraph();
releaseRestrictionData();
LOGGER.info("Finished reading OSM file: {}, nodes: {}, edges: {}, zero distance edges: {}",
osmFile.getAbsolutePath(), nf(baseGraph.getNodes()), nf(baseGraph.getEdges()), nf(zeroCounter));
}
/**
* @return the timestamp given in the OSM file header or null if not found
*/
public Date getDataDate() {
return osmDataDate;
}
/**
* This method is called for each way during the first and second pass of the {@link WaySegmentParser}. All OSM
* ways that are not accepted here and all nodes that are not referenced by any such way will be ignored.
*/
protected boolean acceptWay(ReaderWay way) {
// ignore broken geometry
if (way.getNodes().size() < 2)
return false;
// ignore multipolygon geometry
if (!way.hasTags())
return false;
return osmParsers.acceptWay(way);
}
/**
* @return true if the given node should be duplicated to create an artificial edge. If the node turns out to be a
* junction between different ways this will be ignored and no artificial edge will be created.
*/
protected boolean isBarrierNode(ReaderNode node) {
return node.hasTag("barrier") || node.hasTag("ford");
}
/**
* @return true if the length of the way shall be calculated and added as an artificial way tag
*/
protected boolean isCalculateWayDistance(ReaderWay way) {
return isFerry(way);
}
private boolean isFerry(ReaderWay way) {
return FerrySpeedCalculator.isFerry(way);
}
/**
* This method is called during the second pass of {@link WaySegmentParser} and provides an entry point to enrich
* the given OSM way with additional tags before it is passed on to the tag parsers.
*/
protected void setArtificialWayTags(PointList pointList, ReaderWay way, double distance, List