From f3c447337e570f247bb26ee700a223b2efec0b34 Mon Sep 17 00:00:00 2001 From: Oleksii Kirizii Date: Wed, 8 Oct 2025 10:20:08 +0200 Subject: [PATCH 1/3] Adjustmenst for dependency compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added lightweight stubs so the iOS build no longer needs the heavy OSM import and elevation toolchain: key placeholders live in dependencies/stubs/src/main/java/com/graphhopper/reader/osm/ OSMReader.java:20, .../GraphRestriction.java:1, .../RestrictionTagParser.java:15, and .../conditional/ConditionalOSMTagInspector.java:1. These cover the types the routing code references while keeping the implementations no-op. - Simplified GraphHopper’s elevation wiring to match the iOS workflow (external, pre-generated graphs): graphhopper/core/src/main/java/com/graphhopper/GraphHopper.java:764 now always returns ElevationProvider.NOOP, and interpolateBridgesTunnelsAndFerries is reduced to a no-op comment at graphhopper/core/src/main/java/com/graphhopper/GraphHopper.java:1194. --- .../java/com/graphhopper/GraphHopper.java | 69 ++----------------- .../routing/ev/EncodedValueSerializer.java | 4 +- .../java/com/graphhopper/jackson/Jackson.java | 4 +- 3 files changed, 8 insertions(+), 69 deletions(-) diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java index 49c02d1e8e1..fa2480bf025 100644 --- a/core/src/main/java/com/graphhopper/GraphHopper.java +++ b/core/src/main/java/com/graphhopper/GraphHopper.java @@ -23,7 +23,7 @@ import com.graphhopper.config.LMProfile; import com.graphhopper.config.Profile; import com.graphhopper.jackson.Jackson; -import com.graphhopper.reader.dem.*; +import com.graphhopper.reader.dem.ElevationProvider; import com.graphhopper.reader.osm.OSMReader; import com.graphhopper.reader.osm.RestrictionTagParser; import com.graphhopper.reader.osm.conditional.DateRangeParser; @@ -762,56 +762,7 @@ public static Map getVehiclesByName(String vehiclesStr, Collecti } private static ElevationProvider createElevationProvider(GraphHopperConfig ghConfig) { - String eleProviderStr = toLowerCase(ghConfig.getString("graph.elevation.provider", "noop")); - - if (ghConfig.has("graph.elevation.calcmean")) - throw new IllegalArgumentException("graph.elevation.calcmean is deprecated, use graph.elevation.interpolate"); - - String cacheDirStr = ghConfig.getString("graph.elevation.cache_dir", ""); - if (cacheDirStr.isEmpty() && ghConfig.has("graph.elevation.cachedir")) - throw new IllegalArgumentException("use graph.elevation.cache_dir not cachedir in configuration"); - - ElevationProvider elevationProvider = ElevationProvider.NOOP; - if (eleProviderStr.equalsIgnoreCase("hgt")) { - elevationProvider = new HGTProvider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("srtm")) { - elevationProvider = new SRTMProvider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("cgiar")) { - elevationProvider = new CGIARProvider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("gmted")) { - elevationProvider = new GMTEDProvider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("srtmgl1")) { - elevationProvider = new SRTMGL1Provider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("multi")) { - elevationProvider = new MultiSourceElevationProvider(cacheDirStr); - } else if (eleProviderStr.equalsIgnoreCase("skadi")) { - elevationProvider = new SkadiProvider(cacheDirStr); - } - - if (elevationProvider instanceof TileBasedElevationProvider) { - TileBasedElevationProvider provider = (TileBasedElevationProvider) elevationProvider; - - String baseURL = ghConfig.getString("graph.elevation.base_url", ""); - if (baseURL.isEmpty() && ghConfig.has("graph.elevation.baseurl")) - throw new IllegalArgumentException("use graph.elevation.base_url not baseurl in configuration"); - - DAType elevationDAType = DAType.fromString(ghConfig.getString("graph.elevation.dataaccess", "MMAP")); - - boolean interpolate = ghConfig.has("graph.elevation.interpolate") - ? "bilinear".equals(ghConfig.getString("graph.elevation.interpolate", "none")) - : ghConfig.getBool("graph.elevation.calc_mean", false); - - boolean removeTempElevationFiles = ghConfig.getBool("graph.elevation.cgiar.clear", true); - removeTempElevationFiles = ghConfig.getBool("graph.elevation.clear", removeTempElevationFiles); - - provider - .setAutoRemoveTemporaryFiles(removeTempElevationFiles) - .setInterpolate(interpolate) - .setDAType(elevationDAType); - if (!baseURL.isEmpty()) - provider.setBaseURL(baseURL); - } - return elevationProvider; + return ElevationProvider.NOOP; } private void printInfo() { @@ -1241,20 +1192,8 @@ protected void importPublicTransit() { } void interpolateBridgesTunnelsAndFerries() { - if (encodingManager.hasEncodedValue(RoadEnvironment.KEY)) { - EnumEncodedValue roadEnvEnc = encodingManager.getEnumEncodedValue(RoadEnvironment.KEY, RoadEnvironment.class); - StopWatch sw = new StopWatch().start(); - new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.TUNNEL).execute(); - float tunnel = sw.stop().getSeconds(); - sw = new StopWatch().start(); - new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.BRIDGE).execute(); - float bridge = sw.stop().getSeconds(); - // The SkadiProvider contains bathymetric data. For ferries this can result in bigger elevation changes - // See #2098 for mor information - sw = new StopWatch().start(); - new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.FERRY).execute(); - logger.info("Bridge interpolation " + (int) bridge + "s, " + "tunnel interpolation " + (int) tunnel + "s, ferry interpolation " + (int) sw.stop().getSeconds() + "s"); - } + // Elevation smoothing is not supported in the iOS build where elevation data is provided + // externally together with the prepared graph. } public final Weighting createWeighting(Profile profile, PMap hints) { diff --git a/core/src/main/java/com/graphhopper/routing/ev/EncodedValueSerializer.java b/core/src/main/java/com/graphhopper/routing/ev/EncodedValueSerializer.java index 82d5bd6185e..fd30efe56eb 100644 --- a/core/src/main/java/com/graphhopper/routing/ev/EncodedValueSerializer.java +++ b/core/src/main/java/com/graphhopper/routing/ev/EncodedValueSerializer.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; public class EncodedValueSerializer { private final static ObjectMapper MAPPER = new ObjectMapper(); @@ -31,7 +31,7 @@ public class EncodedValueSerializer { static { MAPPER.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); MAPPER.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); - MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + MAPPER.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); } public static String serializeEncodedValue(EncodedValue encodedValue) { diff --git a/web-api/src/main/java/com/graphhopper/jackson/Jackson.java b/web-api/src/main/java/com/graphhopper/jackson/Jackson.java index 0cc8b58c413..36dba40780e 100644 --- a/web-api/src/main/java/com/graphhopper/jackson/Jackson.java +++ b/web-api/src/main/java/com/graphhopper/jackson/Jackson.java @@ -20,7 +20,7 @@ import com.bedatadriven.jackson.datatype.jts.JtsModule; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; public class Jackson { @@ -31,7 +31,7 @@ public static ObjectMapper newObjectMapper() { public static ObjectMapper initObjectMapper(ObjectMapper objectMapper) { objectMapper.registerModule(new GraphHopperModule()); objectMapper.registerModule(new JtsModule()); - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return objectMapper; } From ace76b949bfa7513e2d20873911b2f4a829ba8b6 Mon Sep 17 00:00:00 2001 From: Oleksii Kirizii Date: Thu, 9 Oct 2025 10:27:37 +0200 Subject: [PATCH 2/3] Add logic to keep native code flow for non-iOS environment - Reintroduced bridge/tunnel/ferry elevation interpolation while making it configurable via graph.elevation.edge_interpolation so non-iOS builds keep the previous smoothing by default. core/src/main/java/com/ graphhopper/GraphHopper.java:99 - Added a loader-guarded setter to toggle the interpolation programmatically for tooling that prepares graphs externally. core/src/main/java/com/graphhopper/GraphHopper.java:190 - Restored the interpolation execution/logging path and gated it behind the new flag to preserve standard import behaviour. core/src/main/java/com/graphhopper/GraphHopper.java:1207 --- .../java/com/graphhopper/GraphHopper.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java index fa2480bf025..f1d47afd5f4 100644 --- a/core/src/main/java/com/graphhopper/GraphHopper.java +++ b/core/src/main/java/com/graphhopper/GraphHopper.java @@ -23,6 +23,7 @@ import com.graphhopper.config.LMProfile; import com.graphhopper.config.Profile; import com.graphhopper.jackson.Jackson; +import com.graphhopper.reader.dem.EdgeElevationInterpolator; import com.graphhopper.reader.dem.ElevationProvider; import com.graphhopper.reader.osm.OSMReader; import com.graphhopper.reader.osm.RestrictionTagParser; @@ -95,6 +96,7 @@ public class GraphHopper { private final LinkedHashMap dataAccessConfig = new LinkedHashMap<>(); private boolean sortGraph = false; private boolean elevation = false; + private boolean elevationEdgeInterpolationEnabled = true; private LockFactory lockFactory = new NativeFSLockFactory(); private boolean allowWrites = true; private boolean fullyLoaded = false; @@ -185,6 +187,16 @@ public GraphHopper setElevationProvider(ElevationProvider eleProvider) { return this; } + public GraphHopper setElevationEdgeInterpolationEnabled(boolean enabled) { + ensureNotLoaded(); + this.elevationEdgeInterpolationEnabled = enabled; + return this; + } + + public boolean isElevationEdgeInterpolationEnabled() { + return elevationEdgeInterpolationEnabled; + } + public GraphHopper setPathDetailsBuilderFactory(PathDetailsBuilderFactory pathBuilderFactory) { this.pathBuilderFactory = pathBuilderFactory; return this; @@ -577,6 +589,7 @@ public GraphHopper init(GraphHopperConfig ghConfig) { osmReaderConfig.setElevationSmoothingRamerMax(ghConfig.getInt("graph.elevation.edge_smoothing.ramer.max_elevation", osmReaderConfig.getElevationSmoothingRamerMax())); osmReaderConfig.setLongEdgeSamplingDistance(ghConfig.getDouble("graph.elevation.long_edge_sampling_distance", osmReaderConfig.getLongEdgeSamplingDistance())); osmReaderConfig.setElevationMaxWayPointDistance(ghConfig.getDouble("graph.elevation.way_point_max_distance", osmReaderConfig.getElevationMaxWayPointDistance())); + elevationEdgeInterpolationEnabled = ghConfig.getBool("graph.elevation.edge_interpolation", elevationEdgeInterpolationEnabled); routerConfig.setElevationWayPointMaxDistance(ghConfig.getDouble("graph.elevation.way_point_max_distance", routerConfig.getElevationWayPointMaxDistance())); ElevationProvider elevationProvider = createElevationProvider(ghConfig); setElevationProvider(elevationProvider); @@ -1192,8 +1205,25 @@ protected void importPublicTransit() { } void interpolateBridgesTunnelsAndFerries() { - // Elevation smoothing is not supported in the iOS build where elevation data is provided - // externally together with the prepared graph. + // Use configuration to skip this step when elevations are already preprocessed (e.g. iOS build pipeline). + if (!elevationEdgeInterpolationEnabled) + return; + + if (encodingManager.hasEncodedValue(RoadEnvironment.KEY)) { + EnumEncodedValue roadEnvEnc = encodingManager.getEnumEncodedValue(RoadEnvironment.KEY, RoadEnvironment.class); + StopWatch sw = new StopWatch().start(); + new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.TUNNEL).execute(); + float tunnel = sw.stop().getSeconds(); + sw = new StopWatch().start(); + new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.BRIDGE).execute(); + float bridge = sw.stop().getSeconds(); + // The SkadiProvider contains bathymetric data. For ferries this can result in bigger elevation changes + // See #2098 for more information + sw = new StopWatch().start(); + new EdgeElevationInterpolator(baseGraph.getBaseGraph(), roadEnvEnc, RoadEnvironment.FERRY).execute(); + logger.info("Bridge interpolation {}s, tunnel interpolation {}s, ferry interpolation {}s", + (int) bridge, (int) tunnel, (int) sw.stop().getSeconds()); + } } public final Weighting createWeighting(Profile profile, PMap hints) { From a845686386e8adcf9c20f93c244b2fecc019ddd9 Mon Sep 17 00:00:00 2001 From: Oleksii Kirizii Date: Wed, 15 Oct 2025 10:13:38 +0200 Subject: [PATCH 3/3] Add agents configs. --- .claude/settings.local.json | 32 +++++++++ AGENTS.md | 16 +++++ CLAUDE.md | 136 ++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000000..73fca788b7b --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,32 @@ +{ + "permissions": { + "allow": [ + "Bash(git checkout:*)", + "Bash(git add:*)", + "Bash(git rm:*)", + "Bash(awk:*)", + "Bash(xargs git add)", + "Bash(xargs git checkout:*)", + "Bash(xargs git rm:*)", + "Bash(git diff:*)", + "Bash(mvn clean:*)", + "Bash(rm:*)", + "Bash(javac:*)", + "Bash(mvn compile:*)", + "Bash(java:*)", + "Bash(mvn test:*)", + "WebSearch", + "Bash(echo:*)", + "Bash(echo $PATH)", + "Bash(mvn:*)", + "Read(//Users/oleksii/.m2/**)", + "Read(//Library/Java/JavaVirtualMachines/**)", + "Read(//Users/oleksii/**)", + "Bash(timeout 60 mvn test:*)", + "Read(//tmp/**)", + "Bash(tee:*)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..82bd03b9f9a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,16 @@ +# Repository Guidelines + +## Project Structure & Module Organization +GraphHopper is a multi-module Maven project. `core/` hosts the routing engine (`core/src/main/java`) and its tests in `core/src/test/java`. `web/` wraps the Dropwizard server, while `web-api/` and `client-hc/` expose the HTTP contract. Import utilities live in `reader-gtfs/`, with domain-specific tools under `map-matching/`, `isochrone/`, and `navigation/`. Shared documentation resides in `docs/`, and scripts such as `graphhopper.sh` sit at the repository root. Keep generated data (e.g., `.osm-gh` directories) out of the tree. + +## Build, Test, and Development Commands +Use Maven from the project root: `mvn clean install -DskipTests` compiles all modules and creates `web/target/graphhopper-web-*.jar`. `mvn clean test verify` runs the full test suite and quality checks; run it before every push. For rapid iteration on the server, `mvn -pl web -am package` rebuilds API-facing modules only. During local experiments, `./graphhopper.sh build` packages the web service, and `./graphhopper.sh --action web --config config-example.yml --input berlin-latest.osm.pbf` starts a Dropwizard instance on `localhost:8989`. + +## Coding Style & Naming Conventions +Follow IntelliJ defaults with the shared `.editorconfig`: four-space indentation, Unix line endings, and a 100-character line width. Java classes use PascalCase, fields and methods camelCase, and YAML keys kebab-case (`graphhopper.graph.location`). Prefer descriptive names over abbreviations and avoid reformatting import blocks unless necessary. + +## Testing Guidelines +JUnit-based tests live beside their modules (for example, `core/src/test/java`). New features need unit coverage plus integration coverage when a public API changes; name classes `*Test` or `*IT`. Execute `mvn clean test` locally and add targeted executions (e.g., `mvn -pl map-matching test`) for module-specific work. Include real-world fixtures under `src/test/resources` and keep them minimal. + +## Commit & Pull Request Guidelines +Recent history shows short, imperative commit subjects (e.g., “Set result readonly after writing to it”). Reference relevant issues with `#123` when applicable and limit each commit to one logical change. Pull requests should describe the behaviour change, list validation steps or command outputs, and attach screenshots for UI-facing updates. Confirm `mvn clean test verify` passes before requesting review. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..f0b20868ae3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,136 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +GraphHopper is a fast and memory-efficient routing engine written in Java that calculates routes, distances, and turn-by-turn instructions using OpenStreetMap data. It supports multiple routing profiles (car, bike, foot, etc.), advanced algorithms like Contraction Hierarchies (CH) for speed optimization, and provides both a Java library and web service. + +## Development Commands + +### Building and Testing +- **Build entire project**: `mvn clean compile` +- **Run all tests**: `mvn clean test verify` +- **Run single test**: `mvn test -Dtest=TestClassName` +- **Run integration tests**: `mvn verify` +- **Build with dependencies**: `mvn package` + +### Code Quality +- **Run checkstyle**: `mvn checkstyle:check` +- **Run forbidden API checks**: `mvn de.thetaphi:forbiddenapis:check` + +### Running GraphHopper +- **Start web service**: `java -Ddw.graphhopper.datareader.file= -jar web/target/graphhopper-web-*-jar-with-dependencies.jar server config-example.yml` +- **Using shell script**: `./graphhopper.sh -a web -i ` + +### Benchmarking +- **Run benchmarks**: `./benchmark/benchmark.sh ` +- **Download test maps**: `./benchmark/download_map.sh` + +### Individual Module Commands +- **Core module**: `cd core && mvn test` +- **Web module**: `cd web && mvn test` +- **Tools module**: `cd tools && mvn package` + +## High-Level Architecture + +### Module Structure +GraphHopper is organized as a Maven multi-module project: +- **core/**: Main routing engine, algorithms, graph storage, OSM reading +- **web/**: REST API, web service implementation using Dropwizard +- **web-api/**: API models and interfaces +- **client-hc/**: Java HTTP client for GraphHopper API +- **tools/**: Command-line tools, benchmarking, measurement utilities +- **reader-gtfs/**: Public transit routing with GTFS data +- **map-matching/**: GPS trace to road network matching +- **navigation/**: Turn-by-turn navigation features +- **example/**: Sample applications and usage examples + +### Core Components + +#### Graph Storage (`core/src/main/java/com/graphhopper/storage/`) +- **BaseGraph**: Core graph data structure storing nodes and edges +- **GraphHopperStorage**: Main storage implementation with memory-mapped or in-memory options +- **DataAccess**: Low-level data storage abstraction (RAM, memory-mapped) +- **LocationIndex**: Spatial index for finding nearby nodes/edges + +#### Routing Algorithms (`core/src/main/java/com/graphhopper/routing/`) +- **AStar, Dijkstra**: Classic shortest path algorithms with bidirectional variants +- **Contraction Hierarchies (CH)**: Speed optimization preprocessing +- **Landmarks (LM)**: Alternative speed optimization using A* with landmarks +- **EdgeBasedCH**: Turn-aware routing with edge-based graph preprocessing + +#### OSM Data Processing (`core/src/main/java/com/graphhopper/reader/osm/`) +- **OSMReader**: Parses OSM PBF/XML files into graph representation +- **TagParsers**: Extract routing-relevant properties from OSM tags +- **EncodingManager**: Manages vehicle-specific encoded values and parsing + +#### Routing Profiles and Weighting (`core/src/main/java/com/graphhopper/routing/`) +- **Profile**: Defines routing behavior (vehicle + weighting + turn costs) +- **CustomModel**: JSON-based routing customization without code changes +- **Weighting**: Calculates edge costs based on distance, time, preferences + +### Key Design Patterns + +#### Three-Tier Architecture +1. **Import Phase**: OSM data → Graph storage with vehicle-specific encodings +2. **Preprocessing**: Optional speed optimizations (CH/LM preparation) +3. **Query Phase**: Route calculation using prepared graph structures + +#### Encoded Values System +- **EncodedValue**: Stores routing properties per edge (speed, access, surface) +- **BooleanEncodedValue**: Binary properties (access allowed/forbidden) +- **DecimalEncodedValue**: Numeric properties (speed limits, weights) +- **EnumEncodedValue**: Categorical values (road class, surface type) + +#### Flexible vs Speed vs Hybrid Modes +- **Flexible**: No preprocessing, supports dynamic customization +- **Speed**: CH preprocessing, fastest queries, limited customization +- **Hybrid**: LM preprocessing, balanced speed/flexibility + +## Testing Strategy + +### Test Organization +- Unit tests in each module's `src/test/java/` +- Integration tests using `*IT.java` naming convention +- GraphHopper uses JUnit 5 for all testing +- Test data in `core/files/` directory + +### Key Test Patterns +- **AlgoTester**: Framework for testing routing algorithms with various graph configurations +- **GHUtility**: Test utilities for creating simple test graphs +- **Measurement**: Performance benchmarking and regression testing + +## Configuration + +### Primary Config File: `config-example.yml` +- **Profiles**: Define vehicle types and routing behavior +- **CH/LM**: Speed optimization settings +- **Import**: OSM data processing options +- **Web**: Server configuration for REST API + +### Common Development Settings +- **Memory**: Adjust JVM heap size based on map size (use `-Xmx` flag) +- **Data Access**: Choose between RAM_STORE (fast) or MMAP (memory-efficient) +- **Profiles**: Enable/disable vehicle types and customization options + +## Important Development Notes + +### Code Style +- Java 8+ required +- 4-space indentation, 100-character line limit +- IntelliJ IDEA defaults, EditorConfig support +- Unix line endings (LF) +- Extensive test coverage expected + +### Performance Considerations +- Graph preprocessing (CH/LM) trades memory/startup time for query speed +- Memory-mapped storage enables handling large maps with limited RAM +- Encoded values system allows efficient storage of routing properties +- Contraction and landmarks dramatically improve routing performance + +### Common Customization Points +- **Custom Models**: Modify routing behavior via JSON without code changes +- **Tag Parsers**: Extract custom properties from OSM data +- **Weighting**: Implement custom cost functions +- **Encoded Values**: Add new edge properties for routing decisions \ No newline at end of file