Skip to content

Changelog

[1.0.0] — 2026-05-29

Added

  • Interactive viewer: way splitting, node deletion, and node position drag editing
  • Interactive viewer: nodes can be inserted into OSM ways by dragging the blue midpoint handles between existing nodes in Edit mode
  • Interactive viewer: barrier ways can now be split (✂️ button on nodes), matching the existing road and footway split behaviour; closed barriers are excluded
  • Interactive viewer: vertex-level editing for manual annotations in Edit mode
  • Interactive viewer: tag editing with save and undo support
  • Interactive viewer: audit change log stored in .annotations.json
  • Interactive viewer: feature search by ID or name in the sidebar; search now also matches all OSM tag values and, for annotations, the annotation type and all extra property keys and values (e.g. searching "wall" or "barrier" finds matching annotations)
  • Interactive viewer: category and subtype visibility toggles
  • Interactive viewer: Leaflet.Snap integration for precise annotation alignment
  • Interactive viewer: GPX file import for waypoint overlays
  • Interactive viewer: GPX upload modal with map name input (previously a stub)
  • Interactive viewer: drag-and-drop .mapdata file upload; /api/upload_mapdata validates via MapData.load and saves to the data directory with collision-safe naming
  • Interactive viewer: Tracker mode for live robot position via ROS2
  • Interactive viewer: planner mode can download and parse OSM data on demand
  • Interactive viewer: planning parameters (grid_margin, obstacle_radius, buffer_widths, grid_cost_weight) configurable in all three map creation dialogs (fetch area, GPX upload, planner fetch) via collapsible advanced-options panels; server defaults populate fields on load
  • Path planning module (pathsolver) with A* graph search and cost-grid support
  • Path planning: annotated paths take priority over obstacle cells
  • Path planning: paths-only planning mode (constrained to mapped ways)
  • Path planning: cancellable planning requests
  • New planner config parameters in planner_defaults.yaml: grid_cost_weight, obstacle_radius, and per-type buffer_widths (road, footway, barrier) — previously hardcoded in source
  • OSM response caching: Overpass query results are persisted to a .osm_cache.json sidecar file and reused on subsequent loads when the bounding box matches, avoiding redundant network requests
  • YAML waypoint format as an alternative to GPX
  • map_data_info CLI tool to print statistics about a .mapdata file
  • osm_cloud launch file with configurable grid topic and static transform publishing
  • osm_cloud: dynamic reconfigure support for runtime tuning of max_path_dist, neighbor_cost, and grid_res
  • Documentation site (MkDocs Material)
  • Dedicated Testing documentation page (docs/dev/testing.md) with per-module design notes and guidance for adding new tests
  • pyproject.toml with ruff configuration for code style enforcement, compatible with ROS2 builds
  • Type hints across core and utility modules
  • pytest suite covering core logic and path planning edge cases
  • Expanded test suite: test_overpass.py (retry logic, rate limiting, status polling), test_errors.py (malformed GPX, corrupt files, Overpass timeouts, planning failures), test_parsing.py (OSM element classification and buffering), test_fill_grid.py (footway cost assignment, barrier cell marking), test_viewer_helpers.py (GeoJSON roundtrip, way splitting, change log migration), test_viewer_routes.py (annotation CRUD, path-traversal security, way operations), and extended test_integration.py (OSM cache roundtrip, bbox mismatch, parse_intersections)

Changed

  • Interactive viewer: GPX download now exports a <trk><trkseg><trkpt> track by default; a Track / Waypoints toggle in the planner panel switches back to the legacy <wpt> format
  • Interactive viewer: annotation vertex handles in Edit mode now only appear when the annotation is clicked, not for all annotations at once
  • Interactive viewer: annotation vertex handles now use the same orange circle + midpoint style as OSM node editing, replacing Leaflet.draw square handles
  • Interactive viewer: transparent overlay markers provide larger click/drag hit targets for OSM nodes, annotation vertices, and planner waypoints without changing their visual appearance
  • Interactive viewer: node drag in Edit mode is more responsive
  • visualize_mapdata CLI tool removed; the browser-based viewer supersedes it
  • grid_cost_weight, obstacle_radius, and buffer_widths are now per-run arguments to grid_astar, RRTStar, and ReplanPath; osm_margin + reserve_margin replaced with a single grid_margin constant (150 m default) accepted as a per-call override in MapData.__init__, parse_osm_nodes, and separate_ways
  • MapData.get_points() now vectorizes UTM conversion by passing full lat/lon arrays to utm.from_latlon in one call instead of looping per node; all nodes are projected into the map's zone for consistency
  • RRTStar now supports Informed RRT* sampling (informed=True, default): once an initial path is found, random samples are drawn from an ellipsoidal subset defined by the current best cost, accelerating convergence toward the optimum
  • RRTStar now supports adaptive neighbor radius (adaptive_radius=True, default): the rewiring radius shrinks as γ·√(log n / n) so the number of rewiring checks stays bounded while preserving asymptotic optimality
  • smooth_path now returns the best collision-free intermediate state instead of reverting to the original path entirely when a smoothed segment collides with an obstacle
  • ReplanPath refactored into focused sub-modules: grid construction moved to PathGrid (pathsolver/grid_constructor.py), path smoothing to smooth_path (pathsolver/smoothing.py), and matplotlib debug visualization to visualize_replan (pathsolver/visualizer.py)
  • Core architecture split into modular components: OverpassClient, parsing, serialization
  • Config loading centralized to map_data/utils/config.py, eliminating duplicated YAML-loading logic from map_data.py and replan.py
  • Logging configuration centralized in setup_logging() (map_data/utils/config.py); info.py, create_mapdata.py, and viewer/app.py now call it inside main() instead of invoking logging.basicConfig at module level with inconsistent formats
  • .mapdata serialisation migrated from pickle to JSON + WKT; legacy pickle support was subsequently removed for security reasons
  • Overpass queries parallelised for faster map data loading
  • Way class refactored to a @dataclass with full type hints
  • os.path replaced with pathlib.Path throughout the codebase
  • Code formatting standardized via ruff across all source modules
  • pyproject.toml and setup.py aligned for ROS2 build compatibility

Fixed

  • visualizer.py: swapped X/Y axis labels corrected — Easting is now on the X axis, Northing on Y
  • Interactive viewer: node drag in Edit mode missed clicks intermittently because canvas node markers rendered below the SVG ghost layer; node markers now use the SVG renderer so events reach them directly
  • Interactive viewer: adding a node to a buffered (Polygon) way drew a faint spike from the buffer outline back to the new node position because apply_added_nodes inserted the centerline coordinate into the exterior ring of the buffer polygon; geometry is now left unchanged for Polygon ways and only way.nodes is updated
  • Interactive viewer: split segments of buffered footways and barriers were rendered thinner than the original after a node had been added to the way; the spike inserted into the buffer polygon corrupted its area/perimeter, causing split_way to calculate a smaller-than-correct buffer radius
  • Interactive viewer: splitting a way at a synthetic (user-added) node failed silently because apply_added_nodes was not called before split_way in the segments and node-list endpoints; synthetic nodes are now inserted into the way geometry and an extended nodes cache is built so the split resolves correctly
  • Interactive viewer: added nodes did not appear anywhere in the sidebar; the add_node event is now written to the change log on creation and removed on undo, and added-node entries are shown in the Annotations panel with an undo button
  • Interactive viewer: deleting one segment of a split way caused the entire original way to disappear on the next file reload; segment deletions are now stored under their virtual ID ("<id>:<index>") so only the deleted segment is suppressed while the remaining segments survive
  • Interactive viewer: reverting any annotation edit (tag override, node deletion, node move) on a way that had also been split left the stale pre-revert geometry on the map alongside the newly restored geometry until page reload; _reloadWay now always uses the segments endpoint so split virtual layers (id:n) are atomically replaced
  • Interactive viewer: Closed roads and footways (e.g. roundabouts) were rendered as filled polygons instead of an annular ring: buffer_line now converts a closed-loop Polygon to a LineString before buffering, unless the way carries area=yes
  • Interactive viewer: tag change-log entries silently disappeared from the changes panel after any metadata refresh (refreshMetadata / loadMapData) because tagMap used numeric keys while the server's change_log stores tag ids as strings; both call-sites now normalise to string keys
  • Interactive viewer: _reselectFeature and focusFeatureById now compare String(_featureId) === String(wayId); previously strict equality failed to reselect real OSM ways (numeric _featureId) after a reload that converted the ID to a string, leaving the feature visually deselected
  • Interactive viewer: duplicate click listeners on way-edit-save and way-edit-add-prop-btn caused double row insertion and double API calls on each action
  • Interactive viewer: planner mousemove/mouseup handlers accumulated on the map with each redraw() call; handlers are now tracked in _mapDragListeners and removed via map.off() before each redraw
  • Interactive viewer: fetch_area and OSM data parsing now run in a background thread; the route returns a task ID immediately and the client polls /api/fetch_area/<task_id> for completion, preventing UI hangs and WebSocket timeouts during long Overpass fetches
  • Annotation deletion via the Del key in the viewer
  • Path traversal vulnerability in viewer API: user-supplied file parameter is now validated against the resolved data directory before any file access
  • /api/fetch_area now rejects requests where min_lat >= max_lat or min_lon >= max_lon
  • parse_yaml_file now wraps all parse errors in a try/except and returns [] with a log message, matching the error contract of parse_gpx_file
  • Path planning with split ways
  • Thread-safe cancellation in the replanning module
  • create_mapdata node: existing file load was missing the .mapdata suffix, causing MapData.load to receive an incorrect path
  • create_mapdata node: --download flag was passed as a positional argument to process_map_data, now correctly passed as a keyword argument
  • Multi-zone UTM boundary warning when loaded area spans two UTM zones