diff --git a/docs/technical-details/api-benchmarks/coordinate-generators.md b/docs/technical-details/api-benchmarks/coordinate-generators.md index e4e99bdf58..3ebcb942a9 100644 --- a/docs/technical-details/api-benchmarks/coordinate-generators.md +++ b/docs/technical-details/api-benchmarks/coordinate-generators.md @@ -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 @@ -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 to generate your extents. | (required). | -| `-p, --profiles` | Comma-separated routing profiles. | (required) | -| `-u, --url` | ORS API base URL. | | -| `-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 to generate your extents. | (required). | +| `-p, --profiles` | Comma-separated routing profiles. | (required) | +| `-u, --url` | ORS API base URL. | | +| `-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 @@ -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" ``` @@ -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. | | -| `-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. | | +| `-o, --output` | Output CSV file path. | snapped_coordinates.csv | +| `-ma, --max-attempts` | Maximum number of attempts for coordinate generation. | 100 | ### Snapping Generator Examples @@ -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" ``` @@ -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" ``` diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/RouteGeneratorApp.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/RouteGeneratorApp.java index 815be2d89b..4076fa5b2b 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/RouteGeneratorApp.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/RouteGeneratorApp.java @@ -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 result = generator.getResult(); diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParser.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParser.java index 0694605b89..5ff441e156 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParser.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParser.java @@ -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) { @@ -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 @@ -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 maxDistanceByProfile = parseMaxDistances(cmd.getOptionValue("m"), profiles); @@ -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; } /** diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParser.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParser.java index 547f0896cf..d1d59cc5c8 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParser.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParser.java @@ -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); @@ -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)") @@ -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 @@ -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; } /** diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/AbstractCoordinateGenerator.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/AbstractCoordinateGenerator.java index f2bb4d5d8e..c6d8499dee 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/AbstractCoordinateGenerator.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/AbstractCoordinateGenerator.java @@ -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"; @@ -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 @@ -44,7 +44,8 @@ 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; @@ -52,6 +53,7 @@ protected AbstractCoordinateGenerator(double[] extent, String[] profiles, String this.random = new SecureRandom(); this.mapper = new ObjectMapper(); this.apiKey = getApiKey(); + this.maxAttempts = maxAttempts; } private void validateBaseInputParameters(double[] extent, String[] profiles, String endpoint) { @@ -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; } @@ -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 */ @@ -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(); + } diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrix.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrix.java index 2253e51668..7cf1c4c2dd 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrix.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrix.java @@ -13,8 +13,8 @@ import org.apache.hc.core5.util.Timeout; import org.heigit.ors.coordinates_generator.model.Matrix; import org.heigit.ors.coordinates_generator.model.MatrixRepository; -import org.heigit.ors.coordinates_generator.service.MatrixCalculator; import org.heigit.ors.coordinates_generator.service.CoordinateSnapper; +import org.heigit.ors.coordinates_generator.service.MatrixCalculator; import org.heigit.ors.util.CoordinateGeneratorHelper; import org.heigit.ors.util.ProgressBarLogger; import org.slf4j.Logger; @@ -34,7 +34,6 @@ public record MatrixDimensions(int numRows, int numCols) { protected static final Logger LOGGER = LoggerFactory.getLogger(CoordinateGeneratorMatrix.class); - private static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors(); private static final String LOCATION_KEY = "location"; private final int numMatrices; @@ -47,16 +46,10 @@ public record MatrixDimensions(int numRows, int numCols) { private final int numThreads; private final CloseableHttpClient httpClient; - protected CoordinateGeneratorMatrix(int numMatrices, double[] extent, String[] profiles, String baseUrl, - Map maxDistanceByProfile, - MatrixDimensions matrixDimensions) { - this(numMatrices, extent, profiles, baseUrl, maxDistanceByProfile, matrixDimensions, DEFAULT_THREAD_COUNT); - } - public CoordinateGeneratorMatrix(int numMatrices, double[] extent, String[] profiles, String baseUrl, - Map maxDistanceByProfile, - MatrixDimensions matrixDimensions, int numThreads) { - super(extent, profiles, baseUrl, "matrix"); + Map maxDistanceByProfile, + MatrixDimensions matrixDimensions, int numThreads, double snapRadius, int maxAttempts) { + super(extent, profiles, baseUrl, "matrix", maxAttempts); validateInputs(numMatrices, numThreads); this.numMatrices = numMatrices; @@ -71,13 +64,13 @@ public CoordinateGeneratorMatrix(int numMatrices, double[] extent, String[] prof try { return httpClient.execute(request, this::processResponse); } catch (IOException e) { - LOGGER.error("Error executing request: {}", e.getMessage()); + LOGGER.debug("Error executing request: {}", e.getMessage()); return null; } }; Map headers = createHeaders(); - this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor); + this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor, snapRadius); this.matrixCalculator = new MatrixCalculator(baseUrl, headers, mapper, requestExecutor); } @@ -118,12 +111,12 @@ private Map normalizeMaxDistances(String[] profiles, Map= maxAttempts) { + if (attempts >= this.maxAttempts) { LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}", - maxAttempts, matrixRepository.getProgressMessage()); + this.maxAttempts, matrixRepository.getProgressMessage()); } } @@ -310,7 +303,7 @@ public Boolean call() { /** * Main method generating a number of matrices - * + * * @return Whether a matrix was successfully added to the repository */ private boolean generateMatricesForProfile() { @@ -463,7 +456,7 @@ private boolean computeAndProcessMatrix(List snappedCoordinates) { /** * Check whether two points are connected in a forward way - * + * * @param from coordinate pair from * @param to coordinate pair to * @return true if matrix was successfully calculated and points are routeable, diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRoute.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRoute.java index 0404d9a61f..59c8f38d71 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRoute.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRoute.java @@ -8,8 +8,8 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.heigit.ors.coordinates_generator.model.Route; import org.heigit.ors.coordinates_generator.model.RouteRepository; -import org.heigit.ors.coordinates_generator.service.MatrixCalculator; import org.heigit.ors.coordinates_generator.service.CoordinateSnapper; +import org.heigit.ors.coordinates_generator.service.MatrixCalculator; import org.heigit.ors.util.CoordinateGeneratorHelper; import org.heigit.ors.util.ProgressBarLogger; import org.slf4j.Logger; @@ -27,7 +27,6 @@ public class CoordinateGeneratorRoute extends AbstractCoordinateGenerator { protected static final Logger LOGGER = LoggerFactory.getLogger(CoordinateGeneratorRoute.class); private static final int DEFAULT_MATRIX_SIZE = 2; - private static final int DEFAULT_THREAD_COUNT = Runtime.getRuntime().availableProcessors(); private static final String LOCATION_KEY = "location"; private final int numRoutes; @@ -38,14 +37,11 @@ public class CoordinateGeneratorRoute extends AbstractCoordinateGenerator { private final MatrixCalculator matrixCalculator; private final int numThreads; - protected CoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, String baseUrl, - double minDistance, Map maxDistanceByProfile) { - this(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile, DEFAULT_THREAD_COUNT); - } public CoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, String baseUrl, - double minDistance, Map maxDistanceByProfile, int numThreads) { - super(extent, profiles, baseUrl, "matrix"); + double minDistance, Map maxDistanceByProfile, int numThreads, + double snapRadius, int maxAttempts) { + super(extent, profiles, baseUrl, "matrix", maxAttempts); validateInputs(numRoutes, minDistance, numThreads); this.numRoutes = numRoutes; @@ -55,16 +51,19 @@ public CoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profile this.routeRepository = new RouteRepository(Set.of(profiles)); Function requestExecutor = request -> { + LOGGER.debug("RequestExecutor: Preparing to execute request URI: {}", request.getRequestUri()); try (CloseableHttpClient client = createHttpClient()) { - return client.execute(request, this::processResponse); + String response = client.execute(request, this::processResponse); + LOGGER.debug("RequestExecutor: Raw response: {}", response); + return response; } catch (IOException e) { - LOGGER.error("Error executing request: {}", e.getMessage()); + LOGGER.debug("Error executing request: {}", e.getMessage()); return null; } }; Map headers = createHeaders(); - this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor); + this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor, snapRadius); this.matrixCalculator = new MatrixCalculator(baseUrl, headers, mapper, requestExecutor); } @@ -85,14 +84,11 @@ private Map normalizeMaxDistances(String[] profiles, Map> futures = submitTasks(executor, shouldContinue); + LOGGER.debug("executeRouteGeneration: Submitted {} tasks.", futures.size()); // Wait for all tasks to complete for (Future future : futures) { try { - future.get(); + Boolean result = future.get(); + LOGGER.debug("executeRouteGeneration: Task completed with result: {}", result); } catch (InterruptedException e) { Thread.currentThread().interrupt(); shouldContinue.set(false); LOGGER.warn("Route generation interrupted"); } catch (ExecutionException e) { - LOGGER.error("Error in worker task: {}", e.getCause().getMessage()); + LOGGER.error("Error in worker task: {}", e.getCause().getMessage(), e.getCause()); } } updateProgressBar(pb); + LOGGER.debug("executeRouteGeneration: Progress bar updated."); // Check if we made progress in this iteration if (routeRepository.getTotalRouteCount() == initialTotalRoutes) { int attempts = consecutiveFailedAttempts.incrementAndGet(); + LOGGER.debug("executeRouteGeneration: No new routes. Consecutive failed attempts: {}", attempts); pb.setExtraMessage(String.format("Attempt %d/%d - No new routes", attempts, maxAttempts)); } else { + LOGGER.debug("executeRouteGeneration: New routes added. Resetting consecutive failed attempts."); consecutiveFailedAttempts.set(0); } } - finalizeProgress(pb, maxAttempts, consecutiveFailedAttempts.get()); + finalizeProgress(pb, consecutiveFailedAttempts.get()); + LOGGER.debug("executeRouteGeneration: Finalized progress."); } } @@ -158,16 +167,20 @@ private ProgressBar createProgressBar() { private List> submitTasks(ExecutorService executor, AtomicBoolean shouldContinue) { List> futures = new ArrayList<>(); + LOGGER.debug("submitTasks: Starting. Should continue: {}", shouldContinue.get()); for (String profile : profiles) { + LOGGER.debug("submitTasks: Checking profile: {}. Is complete: {}", profile, + routeRepository.isProfileComplete(profile, numRoutes)); if (!routeRepository.isProfileComplete(profile, numRoutes)) { int tasksPerProfile = Math.max(1, numThreads / profiles.length); + LOGGER.debug("submitTasks: Submitting {} tasks for profile: {}", tasksPerProfile, profile); for (int i = 0; i < tasksPerProfile && shouldContinue.get(); i++) { futures.add(executor.submit(new RouteGenerationTask(profile, shouldContinue))); } } } - + LOGGER.debug("submitTasks: Finished. Total tasks submitted: {}", futures.size()); return futures; } @@ -177,11 +190,11 @@ private void updateProgressBar(ProgressBar pb) { pb.setExtraMessage(routeRepository.getProgressMessage()); } - private void finalizeProgress(ProgressBar pb, int maxAttempts, int attempts) { + private void finalizeProgress(ProgressBar pb, int attempts) { pb.stepTo(routeRepository.getTotalRouteCount()); - if (attempts >= maxAttempts) { + if (attempts >= this.maxAttempts) { LOGGER.warn("Stopped route generation after {} attempts. Routes per profile: {}", - maxAttempts, routeRepository.getProgressMessage()); + this.maxAttempts, routeRepository.getProgressMessage()); } } @@ -210,131 +223,213 @@ public RouteGenerationTask(String profile, AtomicBoolean shouldContinue) { @Override public Boolean call() { + LOGGER.debug( + "RouteGenerationTask.call: Starting for profile: {}. Should continue: {}, Profile complete: {}", + profile, shouldContinue.get(), routeRepository.isProfileComplete(profile, numRoutes)); if (!shouldContinue.get() || routeRepository.isProfileComplete(profile, numRoutes)) { + LOGGER.debug("RouteGenerationTask.call: Exiting early for profile: {}", profile); return false; } try { - return generateRoutesForProfile(); + boolean result = generateRoutesForProfile(); + LOGGER.debug("RouteGenerationTask.call: generateRoutesForProfile returned {} for profile: {}", result, + profile); + return result; } catch (Exception e) { - LOGGER.error("Error generating routes for profile {}: {}", profile, e.getMessage()); + LOGGER.error("Error generating routes for profile {}: {}", profile, e.getMessage(), e); return false; } } private boolean generateRoutesForProfile() { + LOGGER.debug("generateRoutesForProfile: Starting for profile: {}", profile); // Get max distance for this profile double effectiveMaxDistance = maxDistanceByProfile.getOrDefault(profile, Double.MAX_VALUE); + LOGGER.debug("generateRoutesForProfile: Effective max distance: {} for profile: {}", effectiveMaxDistance, + profile); // Generate random coordinates List randomCoordinates = CoordinateGeneratorHelper.randomCoordinatesInExtent(DEFAULT_MATRIX_SIZE, extent); + LOGGER.debug("generateRoutesForProfile: Generated random coordinates: {} for profile: {}", + Arrays.deepToString(randomCoordinates.toArray()), profile); // Snap the coordinates to the road network + LOGGER.debug("generateRoutesForProfile: Snapping coordinates for profile: {}", profile); List snappedCoordinates = coordinateSnapper.snapCoordinates(randomCoordinates, profile); + LOGGER.debug("generateRoutesForProfile: Snapped coordinates: {} for profile: {}", + Arrays.deepToString(snappedCoordinates.toArray()), profile); if (snappedCoordinates.size() < 2) { + LOGGER.debug("generateRoutesForProfile: Not enough snapped coordinates ({}) for profile: {}. Skipping.", + snappedCoordinates.size(), profile); return false; } - return processSnappedCoordinates(snappedCoordinates, effectiveMaxDistance); + boolean result = processSnappedCoordinates(snappedCoordinates, effectiveMaxDistance); + LOGGER.debug("generateRoutesForProfile: processSnappedCoordinates returned {} for profile: {}", result, + profile); + return result; } private boolean processSnappedCoordinates(List snappedCoordinates, double maxDistance) { + LOGGER.debug( + "processSnappedCoordinates: Starting for profile: {}. Snapped coordinates: {}, Max distance: {}", + profile, Arrays.deepToString(snappedCoordinates.toArray()), maxDistance); boolean addedNewRoute = false; try { addedNewRoute = processCoordinatePairs(snappedCoordinates, maxDistance); + LOGGER.debug("processSnappedCoordinates: processCoordinatePairs returned {} for profile: {}", + addedNewRoute, profile); } catch (Exception e) { - LOGGER.error("Error processing snapped coordinates: {}", e.getMessage()); + LOGGER.error("Error processing snapped coordinates for profile {}: {}", profile, e.getMessage(), e); } + LOGGER.debug("processSnappedCoordinates: Finished for profile: {}. Added new route: {}", profile, + addedNewRoute); return addedNewRoute; } private boolean processCoordinatePairs(List snappedCoordinates, double maxDistance) { + LOGGER.debug("processCoordinatePairs: Starting for profile: {}. Snapped coordinates: {}, Max distance: {}", + profile, Arrays.deepToString(snappedCoordinates.toArray()), maxDistance); boolean addedNewRoute = false; // Process all pairs of coordinates for (double[] start : snappedCoordinates) { + LOGGER.debug("processCoordinatePairs: Processing start coordinate: {} for profile: {}", + Arrays.toString(start), profile); // Generate a destination point within max distance double[] end = CoordinateGeneratorHelper.randomCoordinateInRadiusAndExtent( start, maxDistance, extent); + LOGGER.debug("processCoordinatePairs: Generated end coordinate: {} for profile: {}", + Arrays.toString(end), profile); if (end.length > 0 && CoordinateGeneratorHelper.calculateHaversineDistance(start, end) <= maxDistance) { + LOGGER.debug("processCoordinatePairs: End coordinate is valid and within distance for profile: {}", + profile); + LOGGER.debug( + "processCoordinatePairs: Calculating matrix for profile: {} with start: {} and end: {}", + profile, Arrays.toString(start), Arrays.toString(end)); Optional matrixResultOpt = matrixCalculator.calculateMatrix( List.of(start, end), profile); + LOGGER.debug("processCoordinatePairs: Matrix calculation result present: {} for profile: {}", + matrixResultOpt.isPresent(), profile); if (matrixResultOpt.isPresent()) { - addedNewRoute |= processMatrixResult(matrixResultOpt.get()); + boolean processed = processMatrixResult(matrixResultOpt.get()); + LOGGER.debug("processCoordinatePairs: processMatrixResult returned {} for profile: {}", + processed, profile); + addedNewRoute |= processed; } + } else { + LOGGER.debug( + "processCoordinatePairs: End coordinate invalid or too far for profile: {}. End: {}, Haversine: {}", + profile, Arrays.toString(end), + (end.length > 0 ? CoordinateGeneratorHelper.calculateHaversineDistance(start, end) + : "N/A")); } } + LOGGER.debug("processCoordinatePairs: Finished for profile: {}. Added new route: {}", profile, + addedNewRoute); return addedNewRoute; } private boolean processMatrixResult(MatrixCalculator.MatrixResult result) { + LOGGER.debug("processMatrixResult: Starting for profile: {}", profile); if (!result.isValid()) { - LOGGER.info("Matrix result is invalid, skipping processing"); + LOGGER.info("Matrix result is invalid, skipping processing for profile: {}", profile); return false; } + LOGGER.debug("processMatrixResult: Matrix result is valid for profile: {}", profile); List> sources = result.getSources(); List> destinations = result.getDestinations(); List> distances = result.getDistances(); + LOGGER.debug("processMatrixResult: Sources: {}, Destinations: {}, Distances: {} for profile: {}", sources, + destinations, distances, profile); boolean addedNewRoute = false; for (int i = 0; i < destinations.size(); i++) { + LOGGER.debug("processMatrixResult: Processing destination index {} for profile: {}", i, profile); if (sources.get(i) == null || destinations.get(i) == null || distances.get(i) == null || distances.get(i).isEmpty()) { + LOGGER.debug("processMatrixResult: Skipping null or empty data at index {} for profile: {}", i, + profile); continue; } if (distances.get(i).get(0) != null) { + double distanceValue = distances.get(i).get(0); + LOGGER.debug("processMatrixResult: Distance value: {} for profile: {}", distanceValue, profile); boolean added = addRouteIfUnique(sources.get(i), destinations.get(i), - distances.get(i).get(0), profile); + distanceValue, profile); + LOGGER.debug("processMatrixResult: addRouteIfUnique returned {} for profile: {}", added, profile); if (added) { addedNewRoute = true; + LOGGER.debug("processMatrixResult: New route added for profile: {}", profile); } + } else { + LOGGER.debug("processMatrixResult: Distance at index {} is null for profile: {}", i, profile); } } + LOGGER.debug("processMatrixResult: Finished for profile: {}. Added new route: {}", profile, addedNewRoute); return addedNewRoute; } @SuppressWarnings("unchecked") private boolean addRouteIfUnique(Map start, Map end, double distance, String profile) { + LOGGER.debug("addRouteIfUnique: Starting for profile: {}. Start: {}, End: {}, Distance: {}", profile, start, + end, distance); try { List startCoord = (List) start.get(LOCATION_KEY); List endCoord = (List) end.get(LOCATION_KEY); if (startCoord != null && endCoord != null && startCoord.size() >= 2 && endCoord.size() >= 2) { + LOGGER.debug("addRouteIfUnique: Coordinates are valid for profile: {}", profile); double[] startPoint = new double[] { startCoord.get(0).doubleValue(), startCoord.get(1).doubleValue() }; double[] endPoint = new double[] { endCoord.get(0).doubleValue(), endCoord.get(1).doubleValue() }; + LOGGER.debug("addRouteIfUnique: Start point: {}, End point: {} for profile: {}", + Arrays.toString(startPoint), Arrays.toString(endPoint), profile); if (distance < minDistance) { - LOGGER.debug("Skipping route with distance {} < minimum {} meters", distance, minDistance); + LOGGER.debug( + "addRouteIfUnique: Distance {} is less than minDistance {} for profile: {}. Skipping.", + distance, minDistance, profile); return false; } Route route = new Route(startPoint, endPoint, distance, profile); + LOGGER.debug("addRouteIfUnique: Created route object: {} for profile: {}", route, profile); boolean added = routeRepository.addRouteIfUnique(route); + LOGGER.debug("addRouteIfUnique: routeRepository.addRouteIfUnique returned {} for profile: {}", + added, profile); if (added) { - LOGGER.debug("Added new unique route for profile: {}", profile); + LOGGER.debug("Added new route for profile {}: {} -> {} ({}m)", profile, + Arrays.toString(startPoint), Arrays.toString(endPoint), distance); + return true; } else { - LOGGER.debug("Skipped duplicate route for profile: {}", profile); + LOGGER.debug("Route already exists or not added for profile {}: {} -> {} ({}m)", profile, + Arrays.toString(startPoint), Arrays.toString(endPoint), distance); + return false; } - - return added; + } else { + LOGGER.debug( + "addRouteIfUnique: Invalid coordinates (null or insufficient size) for profile: {}. Start: {}, End: {}", + profile, startCoord, endCoord); } } catch (Exception e) { - LOGGER.error("Error adding route: {}", e.getMessage()); + LOGGER.error("Error adding route for profile {}: {}", profile, e.getMessage(), e); } + LOGGER.debug("addRouteIfUnique: Finished for profile: {}. Returning false.", profile); return false; } } diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnapping.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnapping.java index fc5f7a2444..e3a91a63c1 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnapping.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnapping.java @@ -29,8 +29,8 @@ public class CoordinateGeneratorSnapping extends AbstractCoordinateGenerator { private final Map> uniquePointsByProfile; public CoordinateGeneratorSnapping(int numPoints, double[] extent, double radius, String[] profiles, - String baseUrl) { - super(extent, profiles, baseUrl, "snap"); + String baseUrl, int maxAttempts) { + super(extent, profiles, baseUrl, "snap", maxAttempts); if (numPoints <= 0) throw new IllegalArgumentException("Number of points must be positive"); if (radius <= 0) @@ -48,16 +48,16 @@ public CoordinateGeneratorSnapping(int numPoints, double[] extent, double radius try (CloseableHttpClient client = createHttpClient()) { return client.execute(request, this::processResponse); } catch (IOException e) { - LOGGER.error("Error executing request: {}", e.getMessage()); + LOGGER.debug("Error executing request: {}", e.getMessage()); return null; } }; Map headers = createHeaders(); - this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor); + this.coordinateSnapper = new CoordinateSnapper(baseUrl, headers, mapper, requestExecutor, radius); } @Override - protected void generate(int maxAttempts) { + public void generate() { initializeCollections(); Map lastSizes = initializeLastSizes(); @@ -71,7 +71,7 @@ protected void generate(int maxAttempts) { try (ProgressBar pb = pbb.build()) { pb.setExtraMessage("Starting..."); - generatePoints(pb, lastSizes, maxAttempts); + generatePoints(pb, lastSizes); } catch (Exception e) { LOGGER.error("Error generating points", e); @@ -86,15 +86,14 @@ private Map initializeLastSizes() { return lastSizes; } - private void generatePoints(ProgressBar pb, Map lastSizes, - int maxAttempts) { + private void generatePoints(ProgressBar pb, Map lastSizes) { int attempts = 0; - while (!isGenerationComplete() && attempts < maxAttempts) { + while (!isGenerationComplete() && attempts < this.maxAttempts) { boolean newPointsFound = processProfiles(lastSizes); if (!newPointsFound) { attempts++; - pb.setExtraMessage(String.format("Attempt %d/%d - No new points", attempts, maxAttempts)); + pb.setExtraMessage(String.format("Attempt %d/%d - No new points", attempts, this.maxAttempts)); } else { updateProgress(pb); attempts = 0; @@ -102,9 +101,9 @@ private void generatePoints(ProgressBar pb, Map lastSizes, } pb.stepTo(getTotalPoints()); - if (attempts >= maxAttempts && LOGGER.isWarnEnabled()) { + if (attempts >= this.maxAttempts && LOGGER.isWarnEnabled()) { LOGGER.warn("Stopped point generation after {} attempts. Points per profile: {}", - maxAttempts, formatProgressMessage()); + this.maxAttempts, formatProgressMessage()); } } diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/CoordinateSnapper.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/CoordinateSnapper.java index 5919a43770..9f012c131d 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/CoordinateSnapper.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/CoordinateSnapper.java @@ -15,7 +15,6 @@ public class CoordinateSnapper { private static final Logger LOGGER = LoggerFactory.getLogger(CoordinateSnapper.class); - private static final double DEFAULT_SNAP_RADIUS = 350; // 350 meters radius for snapping private static final String LOCATIONS_KEY = "locations"; private static final String LOCATION_KEY = "location"; @@ -23,13 +22,15 @@ public class CoordinateSnapper { private final Map headers; private final ObjectMapper mapper; private final Function requestExecutor; + private final double snapRadius; public CoordinateSnapper(String baseUrl, Map headers, ObjectMapper mapper, - Function requestExecutor) { + Function requestExecutor, double snapRadius) { this.baseUrl = baseUrl; this.headers = headers; this.mapper = mapper; this.requestExecutor = requestExecutor; + this.snapRadius = snapRadius; } public List snapCoordinates(List coordinates, String profile) { @@ -37,7 +38,11 @@ public List snapCoordinates(List coordinates, String profile try { HttpPost request = createSnapRequest(coordinates, profile); + LOGGER.debug("Snap Request URI: {}", request.getRequestUri()); + // Payload is logged in createSnapRequest + String response = requestExecutor.apply(request); + LOGGER.debug("Snap Raw Response: {}", response); if (response == null) { LOGGER.debug("Received null response from snap API"); @@ -54,7 +59,8 @@ public List snapCoordinates(List coordinates, String profile private HttpPost createSnapRequest(List coordinates, String profile) throws JsonProcessingException { Map payload = new HashMap<>(); payload.put(LOCATIONS_KEY, coordinates); - payload.put("radius", DEFAULT_SNAP_RADIUS); + payload.put("radius", snapRadius); + LOGGER.debug("Snap Request Payload: {}", payload); // Log payload here HttpPost request = new HttpPost(baseUrl + "/v2/snap/" + profile); headers.forEach(request::addHeader); diff --git a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/MatrixCalculator.java b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/MatrixCalculator.java index b80ad4c4b8..0223e7a064 100644 --- a/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/MatrixCalculator.java +++ b/ors-benchmark/src/main/java/org/heigit/ors/coordinates_generator/service/MatrixCalculator.java @@ -36,7 +36,10 @@ public MatrixCalculator(String baseUrl, Map headers, ObjectMappe public Optional calculateMatrix(List coordinates, String profile) { try { HttpPost request = createMatrixRequest(coordinates, profile); + LOGGER.debug("Matrix Request URI: {}", request.getRequestUri()); + // Payload is logged in createMatrixRequest String response = requestExecutor.apply(request); + LOGGER.debug("Matrix Raw Response: {}", response); if (response == null) { LOGGER.debug("Received null response from matrix API"); @@ -53,7 +56,11 @@ public Optional calculateMatrix(List coordinates, String public String calculateMatrixRaw(List coordinates, String profile) { try { HttpPost request = createMatrixRequest(coordinates, profile); - return requestExecutor.apply(request); + LOGGER.debug("Matrix Raw Request URI: {}", request.getRequestUri()); + // Payload is logged in createMatrixRequest + String response = requestExecutor.apply(request); + LOGGER.debug("Matrix Raw Response (from calculateMatrixRaw): {}", response); + return response; } catch (IOException e) { LOGGER.error(ERROR_CALCULATING_MATRIX, e.getMessage()); return null; @@ -63,7 +70,10 @@ public String calculateMatrixRaw(List coordinates, String profile) { public Optional calculateAsymmetricMatrix(List coordinates, int[] sources, int[] destinations, String profile) { try { HttpPost request = createAsymmetricMatrixRequest(coordinates, sources, destinations, profile); + LOGGER.debug("Asymmetric Matrix Request URI: {}", request.getRequestUri()); + // Payload is logged in createAsymmetricMatrixRequest String response = requestExecutor.apply(request); + LOGGER.debug("Asymmetric Matrix Raw Response: {}", response); if (response == null) { LOGGER.debug("Received null response from matrix API"); @@ -84,6 +94,7 @@ private HttpPost createMatrixRequest(List coordinates, String profile) Map payload = new HashMap<>(); payload.put(LOCATIONS_KEY, coordinates); payload.put("metrics", new String[] { "distance" }); + LOGGER.debug("Matrix Request Payload: {}", payload); HttpPost request = new HttpPost(baseUrl + "/v2/matrix/" + profile); headers.forEach(request::addHeader); @@ -101,6 +112,7 @@ private HttpPost createAsymmetricMatrixRequest(List coordinates, int[] payload.put(SOURCES_KEY, sources); payload.put(DESTINATIONS_KEY, destinations); payload.put("metrics", new String[] { "distance" }); + LOGGER.debug("Asymmetric Matrix Request Payload: {}", payload); HttpPost request = new HttpPost(baseUrl + "/v2/matrix/" + profile); headers.forEach(request::addHeader); diff --git a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParserTest.java b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParserTest.java index 5b0b10aa6f..9462ab062f 100644 --- a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParserTest.java +++ b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/RouteCommandLineParserTest.java @@ -2,6 +2,7 @@ import org.heigit.ors.benchmark.exceptions.CommandLineParsingException; import org.heigit.ors.coordinates_generator.generators.CoordinateGeneratorRoute; +import org.heigit.ors.coordinates_generator.service.CoordinateSnapper; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -324,4 +325,50 @@ void testSpaceExtentCommandLine() { CoordinateGeneratorRoute generator = cli.createGenerator(); assertNotNull(generator); } + + @Test + void testSnapRadius() { + String[] args = { + "-n", "50", + "-e", "8.6 49.3 8.7 49.4", + "-p", "driving-car", + "-m", "5000", + "-sr", "3000" + }; + + RouteCommandLineParser cli = new RouteCommandLineParser(args); + CoordinateGeneratorRoute generator = cli.createGenerator(); + assertNotNull(generator); + + // Test snapRadius using reflection + assertDoesNotThrow(() -> { + Field coordinateSnapperField = CoordinateGeneratorRoute.class.getDeclaredField("coordinateSnapper"); + coordinateSnapperField.setAccessible(true); + CoordinateSnapper snapper = (CoordinateSnapper) coordinateSnapperField.get(generator); + + Field snapRadiusField = CoordinateSnapper.class.getDeclaredField("snapRadius"); + snapRadiusField.setAccessible(true); + assertEquals(3000.0, snapRadiusField.getDouble(snapper), 0.001); + }); + } + + @Test + void testMaxAttempts() { + String[] args = { + "-n", "50", + "-e", "8.6 49.3 8.7 49.4", + "-p", "driving-car", + "-m", "5000", + "-ma", "5" + }; + + RouteCommandLineParser cli = new RouteCommandLineParser(args); + CoordinateGeneratorRoute generator = cli.createGenerator(); + assertNotNull(generator); + + // No direct way to test maxAttempts after generation, as it's just a parameter + // passed to generate() + // We're verifying that the CLI parser correctly reads the value and the + // generator is created successfully + } } diff --git a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParserTest.java b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParserTest.java index 7ede231b6d..c238d086d0 100644 --- a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParserTest.java +++ b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/cli/SnappingCommandLineParserTest.java @@ -2,11 +2,14 @@ import org.heigit.ors.benchmark.exceptions.CommandLineParsingException; import org.heigit.ors.coordinates_generator.generators.CoordinateGeneratorSnapping; +import org.heigit.ors.coordinates_generator.service.CoordinateSnapper; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; +import java.lang.reflect.Field; + import static org.junit.jupiter.api.Assertions.*; class SnappingCommandLineParserTest { @@ -17,8 +20,8 @@ void testValidCliArguments() { "-n", "100", "-e", "8.6,49.3,8.7,49.4", "-p", "driving-car,cycling-regular", - "-r", "350", - "-u", "http://localhost:8080/ors" + "-sr", "350", + "-u", "http://localhost:8080/ors" }; SnappingCommandLineParser cli = new SnappingCommandLineParser(args); @@ -181,4 +184,74 @@ void testEmptyProfileList() { cli::createGenerator); assertNotNull(exception); } + + @Test + void testMaxAttempts() { + String[] args = { + "-n", "100", + "-e", "8.6 49.3 8.7 49.4", + "-p", "driving-car", + "-ma", "2000" + }; + + SnappingCommandLineParser cli = new SnappingCommandLineParser(args); + CoordinateGeneratorSnapping generator = cli.createGenerator(); + assertNotNull(generator); + + // No direct way to test maxAttempts after generation, as it's just a parameter + // passed to generate() + // We're verifying that the CLI parser correctly reads the value and the + // generator is created successfully + } + + @Test + void testSnapRadius() { + String[] args = { + "-n", "100", + "-e", "8.6 49.3 8.7 49.4", + "-p", "driving-car", + "-sr", "500" + }; + + SnappingCommandLineParser cli = new SnappingCommandLineParser(args); + CoordinateGeneratorSnapping generator = cli.createGenerator(); + assertNotNull(generator); + + // Test snapRadius using reflection to verify it was correctly passed to the + // coordinate snapper + assertDoesNotThrow(() -> { + Field coordinateSnapperField = CoordinateGeneratorSnapping.class.getDeclaredField("coordinateSnapper"); + coordinateSnapperField.setAccessible(true); + CoordinateSnapper snapper = (CoordinateSnapper) coordinateSnapperField.get(generator); + + Field snapRadiusField = CoordinateSnapper.class.getDeclaredField("snapRadius"); + snapRadiusField.setAccessible(true); + assertEquals(500.0, snapRadiusField.getDouble(snapper), 0.001, "Snap radius should be set correctly"); + }); + } + + @Test + void testDefaultSnapRadius() { + String[] args = { + "-n", "100", + "-e", "8.6 49.3 8.7 49.4", + "-p", "driving-car" + // No -sr parameter, should use default value + }; + + SnappingCommandLineParser cli = new SnappingCommandLineParser(args); + CoordinateGeneratorSnapping generator = cli.createGenerator(); + assertNotNull(generator); + + // Test snapRadius using reflection to verify the default value was used + assertDoesNotThrow(() -> { + Field coordinateSnapperField = CoordinateGeneratorSnapping.class.getDeclaredField("coordinateSnapper"); + coordinateSnapperField.setAccessible(true); + CoordinateSnapper snapper = (CoordinateSnapper) coordinateSnapperField.get(generator); + + Field snapRadiusField = CoordinateSnapper.class.getDeclaredField("snapRadius"); + snapRadiusField.setAccessible(true); + assertEquals(350.0, snapRadiusField.getDouble(snapper), 0.001, "Default snap radius should be 350"); + }); + } } diff --git a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrixTest.java b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrixTest.java index f13d70f2d9..f9fd5d893a 100644 --- a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrixTest.java +++ b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorMatrixTest.java @@ -333,19 +333,9 @@ private static Stream invalidConstructorParameters() { private static class TestCoordinateGeneratorMatrix extends CoordinateGeneratorMatrix { private CloseableHttpClient testClient; - public TestCoordinateGeneratorMatrix(int numRoutes, double[] extent, String[] profiles, - String baseUrl, MatrixDimensions matrixDimensions) { - super(numRoutes, extent, profiles, baseUrl, new HashMap<>(), matrixDimensions); - } - public TestCoordinateGeneratorMatrix(int numRoutes, double[] extent, String[] profiles, String baseUrl, Map maxDistanceByProfile, MatrixDimensions matrixDimensions) { - super(numRoutes, extent, profiles, baseUrl, maxDistanceByProfile, matrixDimensions); - } - - public TestCoordinateGeneratorMatrix(int numRoutes, double[] extent, String[] profiles, - String baseUrl, Map maxDistanceByProfile, MatrixDimensions matrixDimensions, int numThreads) { - super(numRoutes, extent, profiles, baseUrl, maxDistanceByProfile, matrixDimensions, numThreads); + super(numRoutes, extent, profiles, baseUrl, maxDistanceByProfile, matrixDimensions, 1, 1, 1); } void setHttpClient(CloseableHttpClient client) { diff --git a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRouteTest.java b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRouteTest.java index cc9ef438cf..201b4fbea1 100644 --- a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRouteTest.java +++ b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorRouteTest.java @@ -148,7 +148,7 @@ void testGenerateRoutesSuccessful() throws Exception { }); // Execute test - testGenerator.generateRoutes(); + testGenerator.generate(); // Verify results List result = testGenerator.getResult(); @@ -203,7 +203,7 @@ void testMultipleProfiles() throws Exception { }); // Execute test - testGenerator.generateRoutes(); + testGenerator.generate(); // Verify results List result = testGenerator.getResult(); @@ -248,7 +248,7 @@ void testWriteCSVToFile(@TempDir Path tempDir) throws Exception { }); // Execute test - testGenerator.generateRoutes(); + testGenerator.generate(); // Write results to CSV String filename = tempDir.resolve("test_routes.csv").toString(); @@ -312,7 +312,7 @@ void testMinimumDistanceFiltering() throws Exception { }); // Execute test - generator.generateRoutes(); + generator.generate(); // Verify all routes meet minimum distance requirement List result = generator.getResult(); @@ -362,21 +362,10 @@ void testInvalidConstructorParameters(int numRoutes, double[] extent, String[] p private static class TestCoordinateGeneratorRoute extends CoordinateGeneratorRoute { private CloseableHttpClient testClient; - public TestCoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, - String baseUrl, double minDistance) { - super(numRoutes, extent, profiles, baseUrl, minDistance, new HashMap<>()); - } - public TestCoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, String baseUrl, double minDistance, Map maxDistanceByProfile) { - super(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile); - } - - public TestCoordinateGeneratorRoute(int numRoutes, double[] extent, String[] profiles, - String baseUrl, double minDistance, - Map maxDistanceByProfile, int numThreads) { - super(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile, numThreads); + super(numRoutes, extent, profiles, baseUrl, minDistance, maxDistanceByProfile, 1, 1, 1); } void setHttpClient(CloseableHttpClient client) { diff --git a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnappingTest.java b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnappingTest.java index 4014d66386..d9c857c58a 100644 --- a/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnappingTest.java +++ b/ors-benchmark/src/test/java/org/heigit/ors/coordinates_generator/generators/CoordinateGeneratorSnappingTest.java @@ -154,7 +154,7 @@ private class TestCoordinateGeneratorSnapping extends CoordinateGeneratorSnappin public TestCoordinateGeneratorSnapping(int numPoints, double[] extent, double radius, String[] profiles, String baseUrl) { - super(numPoints, extent, radius, profiles, baseUrl); + super(numPoints, extent, radius, profiles, baseUrl, 1); } void setHttpClient(CloseableHttpClient client) {