第13章 - 导航与视图控制

第13章:导航与视图控制

13.1 Navigator 概述

Navigator 是 Mapsui 中控制地图视角的核心组件,提供了丰富的导航方法。

public class Navigator
{
    public Viewport Viewport { get; }
    public MMinMax? ZoomLimits { get; set; }
    public MRect? PanLimits { get; set; }
    public bool RotationLock { get; set; }
    
    // 缩放方法
    public void ZoomIn();
    public void ZoomOut();
    public void ZoomTo(double resolution);
    public void ZoomToBox(MRect extent);
    
    // 平移方法
    public void CenterOn(double x, double y);
    public void CenterOn(MPoint center);
    
    // 旋转方法
    public void RotateTo(double rotation);
    
    // 动画导航
    public void CenterOnAndZoomTo(MPoint center, double resolution, long duration = 0);
    public void FlyTo(MRect extent, long duration = 500);
}

13.2 缩放控制

13.2.1 基本缩放

// 放大一级
map.Navigator.ZoomIn();

// 缩小一级
map.Navigator.ZoomOut();

// 缩放到指定分辨率
map.Navigator.ZoomTo(1000);  // 1000 米/像素

// 缩放到指定缩放级别
public void ZoomToLevel(int level)
{
    var resolution = ZoomLevelResolutions.GetResolution(level);
    map.Navigator.ZoomTo(resolution);
}

13.2.2 缩放到范围

// 缩放到指定范围
var extent = new MRect(minX, minY, maxX, maxY);
map.Navigator.ZoomToBox(extent);

// 缩放到要素范围
public void ZoomToFeatures(IEnumerable<IFeature> features)
{
    var extent = GetFeaturesExtent(features);
    if (extent != null)
    {
        map.Navigator.ZoomToBox(extent, MBoxFit.Fit);
    }
}

// 缩放到图层范围
public void ZoomToLayer(ILayer layer)
{
    var extent = layer.Extent;
    if (extent != null)
    {
        map.Navigator.ZoomToBox(extent);
    }
}

13.2.3 缩放限制

// 设置缩放范围限制
map.Navigator.ZoomLimits = new MMinMax(
    minResolution: 0.5,      // 最大放大(最小分辨率)
    maxResolution: 100000    // 最小缩小(最大分辨率)
);

// 基于缩放级别设置限制
map.Navigator.ZoomLimits = new MMinMax(
    ZoomLevelResolutions.GetResolution(19),  // 最大放大到 19 级
    ZoomLevelResolutions.GetResolution(2)    // 最小缩小到 2 级
);

13.3 平移控制

13.3.1 定位到指定点

// 定位到坐标点
map.Navigator.CenterOn(centerX, centerY);

// 定位到 MPoint
var center = new MPoint(centerX, centerY);
map.Navigator.CenterOn(center);

// 定位到经纬度
public void CenterOnLonLat(double lon, double lat)
{
    var mercator = SphericalMercator.FromLonLat(lon, lat);
    map.Navigator.CenterOn(mercator.X, mercator.Y);
}

13.3.2 平移限制

// 限制地图平移范围
var chinaBounds = CoordinateConverter.LonLatExtentToMercator(73, 18, 135, 54);
map.Navigator.PanLimits = chinaBounds;

// 移除平移限制
map.Navigator.PanLimits = null;

13.4 旋转控制

13.4.1 设置旋转角度

// 旋转到指定角度(弧度)
map.Navigator.RotateTo(Math.PI / 4);  // 旋转 45 度

// 旋转到指定角度(度数)
public void RotateToDegrees(double degrees)
{
    var radians = degrees * Math.PI / 180;
    map.Navigator.RotateTo(radians);
}

// 重置旋转
map.Navigator.RotateTo(0);

13.4.2 旋转锁定

// 锁定旋转(禁止用户旋转地图)
map.Navigator.RotationLock = true;

// 允许旋转
map.Navigator.RotationLock = false;

13.5 动画导航

13.5.1 带动画的定位

// 带动画的定位和缩放
var center = new MPoint(centerX, centerY);
map.Navigator.CenterOnAndZoomTo(center, resolution, duration: 500);

// 飞行到指定范围
map.Navigator.FlyTo(extent, duration: 1000);

// 平滑动画定位
public async Task AnimateTo(MPoint target, double targetResolution, int durationMs = 500)
{
    var startCenter = new MPoint(
        map.Navigator.Viewport.CenterX,
        map.Navigator.Viewport.CenterY
    );
    var startResolution = map.Navigator.Viewport.Resolution;
    
    var startTime = DateTime.Now;
    
    while (true)
    {
        var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
        var progress = Math.Min(elapsed / durationMs, 1.0);
        
        // 使用缓动函数
        var easedProgress = EaseOutCubic(progress);
        
        var currentX = startCenter.X + (target.X - startCenter.X) * easedProgress;
        var currentY = startCenter.Y + (target.Y - startCenter.Y) * easedProgress;
        var currentRes = startResolution + (targetResolution - startResolution) * easedProgress;
        
        map.Navigator.CenterOnAndZoomTo(new MPoint(currentX, currentY), currentRes);
        
        if (progress >= 1.0) break;
        
        await Task.Delay(16);  // ~60 FPS
    }
}

private double EaseOutCubic(double t)
{
    return 1 - Math.Pow(1 - t, 3);
}

13.6 视口查询

13.6.1 获取当前视口信息

// 获取视口信息
var viewport = map.Navigator.Viewport;

// 中心点
var centerX = viewport.CenterX;
var centerY = viewport.CenterY;

// 分辨率
var resolution = viewport.Resolution;

// 旋转角度
var rotation = viewport.Rotation;

// 可见范围
var extent = viewport.Extent;

// 视口大小
var width = viewport.Width;
var height = viewport.Height;

13.6.2 坐标转换

// 屏幕坐标 → 地图坐标
var worldPoint = viewport.ScreenToWorld(new MPoint(screenX, screenY));

// 地图坐标 → 屏幕坐标
var screenPoint = viewport.WorldToScreen(new MPoint(worldX, worldY));

13.7 导航历史

13.7.1 实现导航历史

public class NavigationHistory
{
    private readonly Stack<ViewState> _backStack = new();
    private readonly Stack<ViewState> _forwardStack = new();
    private readonly Navigator _navigator;
    
    public bool CanGoBack => _backStack.Count > 1;
    public bool CanGoForward => _forwardStack.Count > 0;
    
    public NavigationHistory(Navigator navigator)
    {
        _navigator = navigator;
    }
    
    public void SaveState()
    {
        var viewport = _navigator.Viewport;
        _backStack.Push(new ViewState
        {
            CenterX = viewport.CenterX,
            CenterY = viewport.CenterY,
            Resolution = viewport.Resolution,
            Rotation = viewport.Rotation
        });
        _forwardStack.Clear();
    }
    
    public void GoBack()
    {
        if (!CanGoBack) return;
        
        _forwardStack.Push(_backStack.Pop());
        var state = _backStack.Peek();
        ApplyState(state);
    }
    
    public void GoForward()
    {
        if (!CanGoForward) return;
        
        var state = _forwardStack.Pop();
        _backStack.Push(state);
        ApplyState(state);
    }
    
    private void ApplyState(ViewState state)
    {
        _navigator.CenterOnAndZoomTo(
            new MPoint(state.CenterX, state.CenterY),
            state.Resolution,
            duration: 300
        );
        _navigator.RotateTo(state.Rotation);
    }
    
    private class ViewState
    {
        public double CenterX { get; set; }
        public double CenterY { get; set; }
        public double Resolution { get; set; }
        public double Rotation { get; set; }
    }
}

13.8 自定义导航控件

13.8.1 导航控制器

public class MapNavigationController
{
    private readonly Map _map;
    private readonly NavigationHistory _history;
    
    public MapNavigationController(Map map)
    {
        _map = map;
        _history = new NavigationHistory(map.Navigator);
    }
    
    public void ZoomIn() => _map.Navigator.ZoomIn();
    public void ZoomOut() => _map.Navigator.ZoomOut();
    public void ResetNorth() => _map.Navigator.RotateTo(0);
    
    public void GoHome()
    {
        // 定义默认视图
        var homeExtent = CoordinateConverter.LonLatExtentToMercator(73, 18, 135, 54);
        _map.Navigator.ZoomToBox(homeExtent);
    }
    
    public void ZoomToLocation(double lon, double lat, int zoomLevel = 15)
    {
        var center = SphericalMercator.FromLonLat(lon, lat);
        var resolution = ZoomLevelResolutions.GetResolution(zoomLevel);
        _map.Navigator.CenterOnAndZoomTo(
            new MPoint(center.X, center.Y),
            resolution,
            duration: 500
        );
    }
    
    public void SaveCurrentView() => _history.SaveState();
    public void GoBack() => _history.GoBack();
    public void GoForward() => _history.GoForward();
}

13.9 本章小结

本章详细介绍了 Mapsui 的导航与视图控制:

  1. Navigator 概述:核心导航组件
  2. 缩放控制:放大、缩小、缩放到范围、缩放限制
  3. 平移控制:定位、平移限制
  4. 旋转控制:旋转角度、旋转锁定
  5. 动画导航:平滑过渡效果
  6. 视口查询:获取当前视口信息
  7. 导航历史:前进、后退功能

在下一章中,我们将学习性能优化与最佳实践。

13.10 思考与练习

  1. 实现一个地图书签功能,保存和恢复多个视图。
  2. 创建一个平滑的飞行动画,支持自定义缓动曲线。
  3. 实现一个鸟瞰模式,展示 3D 倾斜效果。
  4. 创建一个小地图控件,显示当前视图在全图中的位置。
  5. 实现键盘导航控制(方向键平移,+/-缩放)。
posted @ 2026-01-08 14:40  我才是银古  阅读(11)  评论(0)    收藏  举报