Skip to content

Add map rotation feature with GUI slider and CLI support - #876

Merged
louis-e merged 16 commits into
mainfrom
feature/map-rotation
Apr 5, 2026
Merged

louis-e merged 16 commits into
mainfrom
feature/map-rotation

Conversation

@louis-e

@louis-e louis-e commented Apr 3, 2026 •

Copy link
Copy Markdown
Owner

Implement clockwise map rotation (-90 to 90 degrees) that rotates OSM elements, bounding boxes, and elevation data around the bbox center. Includes a rotation slider in the GUI with live map preview, an optional --rotation CLI argument, rotation masking to prevent block placement outside the rotated area, and Laplacian smoothing for elevation edges. Also adds an angle line tool on the map for setting rotation by drawing a reference line along a road.

Also fixes dependency breakage from dependabot PRs: pins bedrock-rs to rev 7ef268b, downgrades nbtx to rev 551c38a, and downgrades rusty-leveldb back to v3 for compatibility with bedrockrs_level.

Implement counterclockwise map rotation (-90 to 90 degrees) that rotates
OSM elements, bounding boxes, and elevation data around the bbox center.
Includes a rotation slider in the GUI with live map preview, an optional
--rotation CLI argument, rotation masking to prevent block placement
outside the rotated area, and Laplacian smoothing for elevation edges.

Also fixes dependency breakage from dependabot PRs: pins bedrock-rs to
rev 7ef268b, downgrades nbtx to rev 551c38a, and downgrades rusty-leveldb
back to v3 for compatibility with bedrockrs_level.

Co-Authored-By: 13raur0 <[email protected]>
Co-Authored-By: XianlinSheng <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Copilot AI review requested due to automatic review settings April 3, 2026 23:51
The previous rotation preview refactor left an extra `});` that
prematurely closed the $(document).ready block, breaking all map
functionality below it.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@github-actions

github-actions Bot commented Apr 3, 2026 •

Copy link
Copy Markdown

⏱️ Benchmark run finished in 0m 35s
🧠 Peak memory usage: 1628 MB

📈 Compared against baseline: 30s
🧮 Delta: 5s
🔢 Commit: 2d2efbc

⚠️ This PR worsens generation time.

📅 Last benchmark: 2026-04-05 16:53:40 UTC

You can retrigger the benchmark by commenting retrigger-benchmark.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a map-rotation feature that can be driven from both the CLI and GUI, rotating generated OSM elements/bounding boxes and attempting to rotate elevation data, plus introduces a rotation “mask” to avoid placing blocks outside the rotated original area. It also updates/pins several Bedrock-related dependencies to restore compatibility after dependabot changes.

Changes:

  • Add a rotate_world transformation (operator + direct API) and apply it from CLI (--rotation) and GUI (slider + live preview).
  • Add Ground::RotationMask and use it during ground generation to skip out-of-rotated-bounds blocks.
  • Pin/downgrade Bedrock-related dependencies (bedrock-rs rev, nbtx rev, rusty-leveldb v3) and update lockfile accordingly.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/map_transformation/rotate/rotator.rs New rotation implementation for bbox/elements/elevation + tests.
src/map_transformation/rotate/mod.rs Exposes rotate operator / helper API.
src/map_transformation/operator.rs Registers "rotate" operator from JSON.
src/map_transformation/mod.rs Exposes new rotate module.
src/main.rs Applies CLI rotation after map transformations.
src/gui/js/main.js Adds rotation slider wiring and sends rotation to backend + preview iframe.
src/gui/js/bbox.js Receives preview rotation message and rotates rectangle display.
src/gui/index.html Adds rotation slider UI controls.
src/gui/css/styles.css Styles rotation slider controls.
src/gui.rs Adds GUI rotation parameter, passes it into generation, applies rotation in pipeline.
src/ground.rs Adds rotation mask + helpers; adds set_elevation_data.
src/ground_generation.rs Skips blocks outside rotated bounds during ground fill.
src/coordinate_system/cartesian/xzbbox/mod.rs Re-exports XZBBoxRect for rotation code.
src/coordinate_system/cartesian/mod.rs Re-exports XZBBoxRect.
src/args.rs Adds --rotation CLI flag + validation.
Cargo.toml Pins bedrock-rs rev, pins nbtx rev, downgrades rusty-leveldb to v3.
Cargo.lock Lockfile updates for the dependency changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/map_transformation/rotate/rotator.rs Outdated
Comment thread src/map_transformation/rotate/rotator.rs Outdated
Comment thread src/map_transformation/rotate/rotator.rs Outdated
Comment thread src/ground_generation.rs
Comment thread src/main.rs
Comment thread src/gui.rs
Comment thread src/gui/index.html Outdated
Comment thread Cargo.toml
louis-e and others added 4 commits April 4, 2026 13:47
- Align nbtx dependency with main's fix (remove rev pin, unify lockfile)
- Fix rotator to use relative coordinates for Ground::level sampling
- Add full upper+lower bounds check for elevation grid padding detection
- Check elevation_enabled before cloning Ground (avoid needless alloc)
- Rotate land-cover grids alongside elevation to keep them aligned
- Rotate spawn point through the same transform in both CLI and GUI
- Fix map preview rotation jitter on zoom (use container-relative coords)
- Add rotation_angle locale key to all 17 translation files

Co-Authored-By: 13raur0 <[email protected]>
Co-Authored-By: XianlinSheng <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The previous fix used map.getPane which doesn't exist in the Leaflet
version bundled with the app. SVG getBBox provides coordinates in the
element's own coordinate system, inherently stable across zoom/pan.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…erlay

- Fix ground_generation.rs passing world coordinates to Ground methods
  that expect bbox-relative coordinates (cover_class, water_distance)
- Remove iframe/tile-pane rotation that caused zoom instability and
  rotated controls; use diamond mask overlay only to show generated area
- Rotate world preview image to match current rotation angle

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Skip world preview overlay when the world was generated with rotation,
  since the rotated image cannot be reliably aligned on the Leaflet map
- Clear world preview when the user changes the rotation angle
- Add rotation_angle to the localization elements map so the label
  updates when switching languages

Co-Authored-By: Claude Opus 4.6 <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 34 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Cargo.toml
Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/main.rs Outdated
Comment thread src/ground_generation.rs
Comment thread src/gui/js/bbox.js Outdated
Comment thread src/gui.rs Outdated
louis-e and others added 2 commits April 4, 2026 19:19
- Fix CI: remove unused Rotator import from rotate/mod.rs
- Pin nbtx git dependency to rev 551c38a
- Extract shared rotate_xz_point helper for spawn rotation
- Consolidate 3 redundant llbbox_to_xzbbox calls in gui.rs Bedrock path
- Fix spawn rotation to use pre-rotation bbox center (was using post-rotation)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Resolve conflicts in Cargo.toml and Cargo.lock: keep main's nbtx
(no rev pin, already fixed in main via #879).

Co-Authored-By: Claude Opus 4.6 <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/gui.rs:936

  • In the skip_osm_objects (terrain-only) branch, rotation is set on args, but no rotation is applied to xzbbox/ground before calling generate_world_with_options. This makes the GUI rotation slider have no effect in terrain-only mode (and may also disable preview unnecessarily). Consider calling rotate_world(rotation_angle, &mut parsed_elements, &mut xzbbox, &mut ground) in this branch as well (parsed_elements is empty).
            // If skip_osm_objects is true (terrain-only mode), skip fetching and processing OSM data
            if skip_osm_objects {
                // Generate ground data (terrain) for terrain-only mode
                let ground = ground::generate_ground_data(&args);

                // Create empty parsed_elements and xzbbox for terrain-only mode
                let parsed_elements = Vec::new();
                let (_coord_transformer, xzbbox) =
                    CoordTransformer::llbbox_to_xzbbox(&args.bbox, args.scale)
                        .map_err(|e| format!("Failed to create coordinate transformer: {}", e))?;

                let _ = data_processing::generate_world_with_options(
                    parsed_elements,
                    xzbbox.clone(),
                    args.bbox,
                    ground,
                    &args,
                    generation_options.clone(),
                );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ground.rs Outdated
Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/gui/js/bbox.js
louis-e and others added 6 commits April 4, 2026 19:41
…map hint

- Add floating-point epsilon tolerance in is_in_rotated_bounds to prevent
  edge strips from being incorrectly masked out
- Remove _generatedRotationAngle tracking and rotation-aware preview skip
  (world preview now works regardless of rotation angle)
- Remove "clear preview on rotation change" logic
- Add hint overlay on map when no bbox is selected

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The JS diamond mask was negating the angle (-angle), causing the
preview to rotate CW while Rust rotates CCW in geographic space.
Verified by computing NE corner through both code paths:
- Rust at +30°: (80.8, 71.65) — correct CCW
- JS at -30°:  (105.8, 21.65) — wrong direction
- JS at +30°:  (80.8, 71.65) — matches Rust

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Remove "Select a preset" prefix, keep just the draw tool hint
- Center horizontally on map with absolute positioning
- Match Leaflet control styling (4px radius, subtle border/shadow)
- Position slightly higher (bottom: 18px)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The preview image covers the expanded post-rotation MC bbox, but
metadata only stores pre-rotation geographic bounds. Leaflet squeezes
the larger image into the smaller geo rectangle, making 10° look like
30-35° rotated. Re-add the guard to skip preview when rotation is
active, and clear preview when the rotation slider changes.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Users expect positive degrees = clockwise rotation when looking at
a map. The internal XZ rotation formula is CCW for positive radians,
so negate the angle at the entry points (rotate_world, rotate_xz_point)
and in the JS diamond mask.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add custom 2-click angle measurement tool to the map toolbar (draw a
  reference line along a road/feature to auto-calculate rotation angle)
- Auto-fill the measured angle into the Rotation Angle setting
- Show toast notification when rotation angle is set
- Remove the gray dead-zone diamond mask overlay from bbox selection
- Adjust hint overlay sizing

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 33 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/args.rs Outdated
Comment thread src/args.rs Outdated
Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/main.rs
Comment thread src/gui/js/bbox.js
Comment thread src/gui/js/bbox.js
Comment thread src/gui.rs
- Correct --rotation help text from "Counterclockwise" to "Clockwise" to
  match actual behavior in rotator.rs
- Add is_finite() check to reject NaN/infinity rotation values
@louis-e

louis-e commented Apr 5, 2026

Copy link
Copy Markdown
Owner Author

retrigger-benchmark

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 33 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/map_transformation/rotate/rotator.rs
Comment thread src/ground.rs
@louis-e
louis-e merged commit 7b24d6a into main Apr 5, 2026
2 checks passed
@louis-e
louis-e deleted the feature/map-rotation branch April 5, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants