nigig-org/crates/apps/map
User 0718743e19
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
nigig-map / test (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
feat(map): implement Phase 2 route overlay system with markers and position puck
Complete overlay rendering system ported from Makepad upstream:

## New Features
- **Route Overlay Rendering**: Route polyline with casing (9px) and fill (5.5px)
  - Traveled portion dimming (alpha 0.30) for navigation progress
  - Additive glow effect (route_glow) for visual enhancement
  - Destination dot at route end
  - Screen-space rendering with viewport clipping

- **Drop Markers**: Professional pin-shaped markers with:
  - Soft ground shadow (ellipse)
  - Triangular tail + circular head pin shape
  - White pip in center
  - 16px tap detection radius for interaction
  - Custom color support per marker

- **Position Puck**: Current location indicator with:
  - Accuracy circle (scales with zoom, 10-28% alpha)
  - Heading wedge (20px tip, shows direction)
  - White ring + blue dot (9px/6.2px)
  - Automatic viewport clipping (60px margin)

## Implementation Details
- **OverlayCamera**: Screen-space transformation system
  - norm_to_screen() converts normalized coords to screen pixels
  - Supports rotation and 2.5D tilt (for future phases)
  - Meters-per-pixel calculation for accuracy circle scaling

- **Integration**: Seamlessly integrated into NigigMapView
  - Added draw_overlay: DrawVector field to widget
  - Added overlay_state: MapOverlayState field
  - Rendering happens after tile passes, before status text
  - Zero overhead when no overlays are active (is_empty() check)

- **Helper Functions**:
  - draw_route(): Multi-pass route rendering with travel dimming
  - draw_marker(): Pin-shaped marker with shadow and highlight
  - draw_puck(): Location indicator with accuracy and heading
  - marker_at(): Hit testing for tap interaction

- **Viewport Enhancement**: Added meters_per_pixel() method
  - Calculates real-world scale for accuracy circle sizing
  - Accounts for latitude-based distortion
  - Used by position puck for realistic accuracy visualization

## Technical Architecture
- Immediate-mode rendering using DrawVector
- Per-frame geometry rebuild (route scale: few hundred points)
- Viewport clipping with margin (24px for routes, 30px for markers)
- Decimation for performance (1.5px threshold on zoom-out)
- Additive blending for glow effects (no HDR required)

## Files Changed
- crates/apps/map/src/overlay.rs (NEW, 379 lines)
- crates/apps/map/src/lib.rs (module registration)
- crates/apps/map/src/view.rs (widget integration, 15 lines added)
- crates/apps/map/src/viewport.rs (meters_per_pixel method, 18 lines)

## API Usage

## Performance
- Zero cost when no overlays (early return on is_empty())
- Efficient viewport clipping reduces overdraw
- Route decimation prevents excessive geometry at low zoom
- All rendering uses GPU-accelerated DrawVector

## Compatibility
- Backward compatible: existing map functionality unchanged
- Overlay state persists across frames (no per-frame allocation)
- Integrates with existing theme system (route colors from theme)
- Supports future 2.5D camera and heading-up rotation

## Testing Recommendations
1. Verify routes render with casing/fill at all zoom levels
2. Test traveled portion dimming updates correctly
3. Verify markers appear at correct screen positions
4. Test position puck accuracy circle scales with zoom
5. Verify heading wedge rotates correctly
6. Test viewport clipping at screen edges

Refs: Phase 2 from MAKEPAD_DEV_BRANCH_GAP_ANALYSIS.md
Built on: Phase 1 (POI icon system, commit ae23d36)
2026-08-01 05:27:00 +00:00
..
benches test(map): implement comprehensive testing & validation (Phase 6) 2026-07-27 16:49:00 +00:00
certs security(map): implement Phase 4 security hardening 2026-07-27 16:27:17 +00:00
fuzz test(map): implement comprehensive testing & validation (Phase 6) 2026-07-27 16:49:00 +00:00
src feat(map): implement Phase 2 route overlay system with markers and position puck 2026-08-01 05:27:00 +00:00
tests ci: require full 40-character SHAs for git dependency revs 2026-07-31 19:53:49 +00:00
API.md docs(map): add comprehensive documentation for map crate (Phase 5) 2026-07-28 17:22:32 +00:00
Cargo.toml ci: require full 40-character SHAs for git dependency revs 2026-07-31 19:53:49 +00:00
README.md docs(map): add comprehensive documentation for map crate (Phase 5) 2026-07-28 17:22:32 +00:00
USER_GUIDE.md docs(map): add comprehensive documentation for map crate (Phase 5) 2026-07-28 17:22:32 +00:00

Nigig Map

A high-performance, offline-capable map rendering widget for Makepad applications.

Overview

Nigig Map is a vector tile renderer designed for Makepad applications. It supports both offline (MBTiles) and online (Overpass API) map data sources, with comprehensive label placement, style customization, and smooth pan/zoom interactions.

Features

  • Offline Maps: Load and render MBTiles files for offline map display
  • Online Maps: Fetch and render map data from Overpass API
  • Vector Tiles: Render vector tiles with fill, stroke, and label layers
  • Label Placement: Intelligent label placement with collision detection
  • Style Customization: Comprehensive style system with zoom-dependent styles
  • Smooth Interactions: Smooth pan, zoom, and pinch gestures
  • Performance Optimized: Optimized for 60 FPS rendering with efficient caching

Architecture

The map renderer follows a modular architecture with clear separation of concerns:

view.rs (1115 lines) - Main widget, orchestrates rendering
├── viewport.rs (538 lines) - Viewport state and transformations
├── cache.rs (786 lines) - Tile caching with LRU eviction
├── scheduler.rs (849 lines) - Tile loading scheduler
├── render_graph.rs - Render graph execution
├── tessellation.rs (597 lines) - Geometry tessellation
├── mvt_parser.rs (711 lines) - MVT tile parsing
├── overpass_parser.rs (282 lines) - Overpass API parsing
├── style.rs (496 lines) - Style compilation
├── label.rs (1098 lines) - Label extraction
├── label_state.rs (487 lines) - Label placement
├── sprite.rs (433 lines) - Sprite rendering
├── tile.rs (303 lines) - Tile types
├── tile_decode.rs (361 lines) - Tile decoding
└── tile_disk.rs (204 lines) - Disk cache

Usage

Basic Usage

use makepad_widgets::*;
use nigig_map::MapView;

live_design!{
    use mod.prelude.widgets.*;
    
    MyApp = {{App}} {
        ui: <Window> {
            map_view = <MapView> {
                center_lon: 36.8219,  // Nairobi
                center_lat: -1.2921,
                zoom: 14.0,
                min_zoom: 10.0,
                max_zoom: 18.0,
                use_local_mbtiles: true,
                local_mbtiles_path: "kenya-shortbread-1.0.mbtiles",
            }
        }
    }
}

Offline Maps (MBTiles)

map_view = <MapView> {
    use_local_mbtiles: true,
    local_mbtiles_path: "kenya-shortbread-1.0.mbtiles",
    use_network: false,
}

Online Maps (Overpass API)

map_view = <MapView> {
    use_local_mbtiles: false,
    use_network: true,
}

Style Customization

map_view = <MapView> {
    style_light: MapThemeStyle {
        background: #xeaf0f5,
        label: #x1f2937,
        
        MapFillRule { group: "building", color: #xd7dee7 },
        MapFillRule { group: "water", color: #xbfe7fb },
        
        MapRoadRule {
            kind: "motorway",
            sort_rank: 700,
            casing_color: #xc1782f,
            casing_width: 6.2,
            center_color: #xffc266,
            center_width: 4.2,
        },
    },
}

Programmatic Control

// Load style from JSON
map_view.load_style_json(style_json)?;

// Enable/disable render passes
map_view.enable_pass(PassType::Label);
map_view.disable_pass(PassType::POI);

// Set zoom range for a pass
map_view.set_pass_zoom_range(PassType::Label, 14.0, 20.0);

// Access render graph
let graph = map_view.render_graph();

API Reference

MapView

The main map widget.

Properties

  • center_lon: f64 - Center longitude (default: 4.9041)
  • center_lat: f64 - Center latitude (default: 52.3676)
  • zoom: f64 - Zoom level (default: 14.0)
  • min_zoom: f64 - Minimum zoom level (default: 11.0)
  • max_zoom: f64 - Maximum zoom level (default: 17.0)
  • dark_theme: bool - Use dark theme (default: false)
  • use_network: bool - Enable network requests (default: true)
  • use_local_mbtiles: bool - Use local MBTiles (default: true)
  • local_mbtiles_path: String - Path to MBTiles file
  • local_tile_cache_dir: String - Path to tile cache directory
  • style_light: MapThemeStyle - Light theme style
  • style_dark: MapThemeStyle - Dark theme style

Methods

  • load_style_json(json_str: &str) -> Result<(), String> - Load style from JSON
  • recompile_style_for_zoom(zoom: f64) - Recompile style for zoom level
  • render_graph() -> &RenderGraph - Get render graph reference
  • enable_pass(pass_type: PassType) - Enable render pass
  • disable_pass(pass_type: PassType) - Disable render pass
  • set_pass_zoom_range(pass_type: PassType, min_zoom: f64, max_zoom: f64) - Set zoom range for pass

MapThemeStyle

Style configuration for map rendering.

Properties

  • background: Vec4f - Background color
  • label: Vec4f - Label color
  • status_text: Vec4f - Status text color
  • fill_rules: Vec<MapFillRule> - Fill rules
  • road_rules: Vec<MapRoadRule> - Road rules
  • waterway_rules: Vec<MapWaterwayRule> - Waterway rules
  • rail_rules: Vec<MapRailRule> - Rail rules

MapFillRule

Fill rule for polygon features.

Properties

  • group: String - Feature group (e.g., "building", "water")
  • value: String - Feature value (e.g., "residential", "yes")
  • color: Vec4f - Fill color

MapRoadRule

Road rendering rule.

Properties

  • kind: String - Road kind (e.g., "motorway", "primary")
  • sort_rank: i32 - Sort rank (higher = drawn on top)
  • casing_color: Vec4f - Casing color
  • casing_width: f32 - Casing width
  • casing_shape_id: f32 - Casing shape ID
  • center_color: Vec4f - Center color
  • center_width: f32 - Center width
  • center_shape_id: f32 - Center shape ID

PassType

Render pass types.

  • PassType::Fill - Fill pass (polygons)
  • PassType::Stroke - Stroke pass (lines)
  • PassType::Label - Label pass (text)
  • PassType::POI - POI pass (points of interest)

Performance

The map renderer is optimized for 60 FPS rendering:

  • Efficient Caching: LRU cache with configurable size (default: 640 tiles)
  • Async Loading: Tiles loaded asynchronously in background threads
  • Deferred Eviction: Tile eviction deferred to prevent use-after-free
  • Optimized Tessellation: Efficient geometry tessellation with signed area calculation
  • Label Placement: Intelligent label placement with collision detection

Testing

The map crate has comprehensive test coverage (80%+):

# Run all tests
cargo test -p nigig-map

# Run specific module tests
cargo test -p nigig-map mvt_parser
cargo test -p nigig-map tessellation
cargo test -p nigig-map style
cargo test -p nigig-map overpass_parser
cargo test -p nigig-map asset_loader

Dependencies

  • makepad-widgets - Makepad widget framework
  • makepad-mbtile-reader - MBTiles file reader
  • makepad-fast-inflate - Fast decompression

License

This project is licensed under the MIT License.

Contributing

Contributions are welcome! Please read the CONTRIBUTING.md for guidelines.

Authors

  • Nigig Team

Acknowledgments

  • Map data from OpenStreetMap contributors
  • MBTiles format from MapBox
  • Makepad framework for widget system