Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 31 additions & 21 deletions docs/technical-details/api-benchmarks/coordinate-generators.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Coordinate Generation Tools

The openrouteservice provides tools for generating test coordinates that can be used for benchmarking, testing, and development purposes. These tools allow you to create realistic coordinates that are compatible with the openrouteservice API and suited for different routing profiles.
The openroutes| `-r, --snap-radius` | Search radius in meters for coordinate snapping. | 350 |
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 100 |vice provides tools for
generating test coordinates that can be used for benchmarking, testing, and development purposes. These tools allow you
to create realistic coordinates that are compatible with the openrouteservice API and suited for different routing
profiles.

## Prerequisites

Expand Down Expand Up @@ -33,16 +37,18 @@ The tool generates random coordinates within a specified bounding box and then u

### Route Generator Options

| Option | Description | Default |
|--------|-------------|---------|
| `-n, --num-routes` | Number of routes to generate. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). Use <https://boundingbox.klokantech.com/> to generate your extents. | (required). |
| `-p, --profiles` | Comma-separated routing profiles. | (required) |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | route_coordinates.csv |
| `-d, --min-distance` | Minimum distance between start and endpoint in an a-to-b routing pair in meters. This is valid for all profiles. | 1 |
| `-m, --max-distances` | Maximum distances in meters **per profile** between the start and endpoint. | (none) |
| `-t, --threads` | Number of threads to use. | Available processors |
| Option | Description | Default |
|-----------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------|
| `-n, --num-routes` | Number of routes to generate. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). Use <https://boundingbox.klokantech.com/> to generate your extents. | (required). |
| `-p, --profiles` | Comma-separated routing profiles. | (required) |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | route_coordinates.csv |
| `-d, --min-distance` | Minimum distance between start and endpoint in an a-to-b routing pair in meters. This is valid for all profiles. | 1 |
| `-m, --max-distances` | Maximum distances in meters **per profile** between the start and endpoint. | (none) |
| `-t, --threads` | Number of threads to use. | Available processors |
| `-sr, --snap-radius` | Search radius in meters for coordinate snapping. | 350 |
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 100 |

### Route Generator Examples

Expand Down Expand Up @@ -76,6 +82,8 @@ Generate 50 routes for both driving-car and cycling-regular profiles with differ
--min-distance 2000 \
--max-distances 5000,3000 \
--threads 4 \
--snap-radius 1500 \
--max-attempts 1500 \
--url http://localhost:8080/ors \
--output routes.csv"
```
Expand All @@ -92,14 +100,15 @@ The tool generates random coordinates within a specified bounding box and then u

### Snapping Generator Options

| Option | Description | Default |
|--------|-------------|---------|
| `-n, --num-points` | Number of points to generate per profile. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
| `-r, --radius` | Search radius in meters. | 350 |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
| Option | Description | Default |
|-----------------------|-------------------------------------------------------|-----------------------------|
| `-n, --num-points` | Number of points to generate per profile. | (required) |
| `-e, --extent` | Bounding box (minLon,minLat,maxLon,maxLat). | (required) |
| `-p, --profiles` | Comma-separated list of routing profiles. | (required) |
| `-sr, --snap-radius` | Search radius in metersfor coordinate snapping. | 350 |
| `-u, --url` | ORS API base URL. | <http://localhost:8080/ors> |
| `-o, --output` | Output CSV file path. | snapped_coordinates.csv |
| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 100 |

### Snapping Generator Examples

Expand All @@ -114,7 +123,7 @@ Generate 100 snapped points for the driving-car profile with a search radius of
-n 100 \
-e 8.6,49.3,8.7,49.4 \
-p driving-car \
-r 500 \
-sr 500 \
-u http://localhost:8080/ors \
-o snapped.csv"
```
Expand All @@ -130,7 +139,8 @@ Generate 50 snapped points for both driving-car and cycling-regular profiles:
--num-points 50 \
--extent 8.681495,49.411721,8.695485,49.419365 \
--profiles driving-car,cycling-regular \
--radius 250 \
--snap-radius 250 \
--max-attempts 1500 \
--url http://localhost:8080/ors \
--output snapped.csv"
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static void main(String[] args) {
CoordinateGeneratorRoute generator = cli.createGenerator();

LOGGER.info("Generating {} routes...", generator.getNumRoutes());
generator.generateRoutes();
generator.generate();
LOGGER.info("\n");

List<Route> result = generator.getResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class RouteCommandLineParser extends CommandLineParser {
private static final Logger LOGGER = LoggerFactory.getLogger(RouteCommandLineParser.class);

private static final String OPT_THREADS = "threads";
private static final String OPT_SNAP_RADIUS = "snap-radius";
private static final String OPT_MAX_ATTEMPTS = "max-attempts";
private static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors();

public RouteCommandLineParser(String[] args) {
Expand Down Expand Up @@ -72,12 +74,25 @@ protected void setupOptions() {
.hasArg()
.desc("Maximum distances between coordinates in meters, comma-separated in profile order (e.g., 5000,3000)")
.build());

options.addOption(Option.builder("t")
.longOpt(OPT_THREADS)
.hasArg()
.desc("Number of threads to use (default: " + DEFAULT_THREAD_COUNT + ")")
.build());

options.addOption(Option.builder("sr")
.longOpt(OPT_SNAP_RADIUS)
.hasArg()
.type(Number.class)
.desc("Search radius in meters for coordinate snapping (default: 1000)")
.build());

options.addOption(Option.builder("ma")
.longOpt(OPT_MAX_ATTEMPTS)
.hasArg()
.type(Number.class)
.desc("Maximum number of attempts for coordinate generation (default: 1000)")
.build());
}

@Override
Expand Down Expand Up @@ -115,6 +130,8 @@ public CoordinateGeneratorRoute createGenerator() {
String[] profiles = parseProfiles(cmd.getOptionValue("p"));
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
double minDistance = Double.parseDouble(cmd.getOptionValue("d", "1"));
double snapRadius = Double.parseDouble(cmd.getOptionValue(OPT_SNAP_RADIUS, "1000"));
int maxAttempts = Integer.parseInt(cmd.getOptionValue(OPT_MAX_ATTEMPTS, String.valueOf(100)));

// Parse the max distances if provided
Map<String, Double> maxDistanceByProfile = parseMaxDistances(cmd.getOptionValue("m"), profiles);
Expand All @@ -123,13 +140,15 @@ public CoordinateGeneratorRoute createGenerator() {

if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}",
"Creating CoordinateGeneratorRoute with numRoutes={}, extent={}, profiles={}, baseUrl={}, minDistance={}, maxDistances={}, numThreads={}, snapRadius={}, maxAttempts={}",
numRoutes, extent, java.util.Arrays.toString(profiles), baseUrl, minDistance, maxDistanceByProfile,
numThreads);
numThreads, snapRadius, maxAttempts);
}

return new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile,
numThreads);
CoordinateGeneratorRoute generator = new CoordinateGeneratorRoute(numRoutes, extent, profiles, baseUrl,
minDistance, maxDistanceByProfile, numThreads, snapRadius, maxAttempts);
generator.generate();
return generator;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

public class SnappingCommandLineParser extends CommandLineParser {
private static final Logger LOGGER = LoggerFactory.getLogger(SnappingCommandLineParser.class);
private static final String OPT_MAX_ATTEMPTS = "max-attempts";

public SnappingCommandLineParser(String[] args) {
super(args);
Expand Down Expand Up @@ -35,8 +36,8 @@ protected void setupOptions() {
.desc("Bounding box (minLon minLat maxLon maxLat)")
.build());

options.addOption(Option.builder("r")
.longOpt("radius")
options.addOption(Option.builder("sr")
.longOpt("snap-radius")
.hasArg()
.type(Number.class)
.desc("Search radius in meters (default: 350)")
Expand All @@ -60,6 +61,13 @@ protected void setupOptions() {
.hasArg()
.desc("Output CSV file path")
.build());

options.addOption(Option.builder("ma")
.longOpt(OPT_MAX_ATTEMPTS)
.hasArg()
.type(Number.class)
.desc("Maximum number of attempts for coordinate generation (default: 100)")
.build());
}

@Override
Expand All @@ -86,14 +94,19 @@ public CoordinateGeneratorSnapping createGenerator() {
int numPoints = Integer.parseInt(cmd.getOptionValue("n"));
double[] extent = parseExtent(cmd.getOptionValue("e"));
String[] profiles = parseProfiles(cmd.getOptionValue("p"));
double radius = Double.parseDouble(cmd.getOptionValue("r", "350"));
double snapRadius = Double.parseDouble(cmd.getOptionValue("sr", "350"));
String baseUrl = cmd.getOptionValue("u", "http://localhost:8080/ors");
int maxAttempts = Integer.parseInt(
cmd.getOptionValue(OPT_MAX_ATTEMPTS, "100"));

LOGGER.info(
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, radius={}, profiles={}, baseUrl={}",
numPoints, extent, radius, profiles, baseUrl);
"Creating CoordinateGeneratorSnapping with numPoints={}, extent={}, snapRadius={}, profiles={}, baseUrl={}, maxAttempts={}",
numPoints, extent, snapRadius, profiles, baseUrl, maxAttempts);

return new CoordinateGeneratorSnapping(numPoints, extent, radius, profiles, baseUrl);
CoordinateGeneratorSnapping generator = new CoordinateGeneratorSnapping(numPoints, extent, snapRadius, profiles,
baseUrl, maxAttempts);
generator.generate();
return generator;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/
public abstract class AbstractCoordinateGenerator {
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCoordinateGenerator.class);
protected static final int DEFAULT_MAX_ATTEMPTS = 100;
protected static final double COORDINATE_PRECISION = 1e-6;
protected static final String DEFAULT_BASE_URL = "http://localhost:8082/ors";

Expand All @@ -35,6 +34,7 @@ public abstract class AbstractCoordinateGenerator {
protected final Random random;
protected final ObjectMapper mapper;
protected final String apiKey;
protected final int maxAttempts;

/**
* Creates a new coordinate generator
Expand All @@ -44,14 +44,16 @@ public abstract class AbstractCoordinateGenerator {
* @param baseUrl API base URL
* @param endpoint API endpoint name (for logging)
*/
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint) {
protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String baseUrl, String endpoint,
int maxAttempts) {
this.baseUrl = baseUrl != null ? baseUrl : DEFAULT_BASE_URL;
validateBaseInputParameters(extent, profiles, endpoint);
this.extent = extent;
this.profiles = profiles.clone();
this.random = new SecureRandom();
this.mapper = new ObjectMapper();
this.apiKey = getApiKey();
this.maxAttempts = maxAttempts;
}

private void validateBaseInputParameters(double[] extent, String[] profiles, String endpoint) {
Expand Down Expand Up @@ -105,16 +107,16 @@ protected CloseableHttpClient createHttpClient() {
* Processes an HTTP response
*/
protected String processResponse(ClassicHttpResponse response) throws IOException {
LOGGER.debug("Received response: {}", new StatusLine(response));
int status = response.getCode();
if (status >= HttpStatus.SC_REDIRECTION) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Received error response: {}", new StatusLine(response));
}
LOGGER.debug("Received error response: {}", new StatusLine(response));
return null;
}

HttpEntity entity = response.getEntity();
if (entity == null) {
LOGGER.debug("Received empty response");
return null;
}

Expand All @@ -130,11 +132,6 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
*/
public abstract void writeToCSV(String filePath) throws IOException;

/**
* Main generation method with specified maximum attempts
*/
protected abstract void generate(int maxAttempts);

/**
* Gets the generated results
*/
Expand All @@ -146,9 +143,8 @@ protected String processResponse(ClassicHttpResponse response) throws IOExceptio
protected abstract void initializeCollections();

/**
* Main generation method with default maximum attempts
* Main generation method
*/
public void generate() {
generate(DEFAULT_MAX_ATTEMPTS);
}
protected abstract void generate();

}
Loading
Loading