开源的DotSpatial虽然十分强大,但是没有比例尺造成不方便。我把我实现的比例尺控件分享出来,给大家使用。记得要监听视野范围变化的事件。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DotSpatial.Data;
using System.Drawing.Drawing2D;
using DotSpatial.Topology;
using System.Drawing.Text;
namespace test
{
public partial class MapScaleControllerView : UserControl
{
/// <summary>
/// 对于当前显示设备每像素的厘米(物理长度)
/// </summary>
private readonly double millimeterPerPixel = 0.0;
private readonly double pixelPerMillimeter = 0.0;
private int iZoomLevel = 0;
private int iScaleLineLength = 0;
private string sDynamicScaleString;
private List<DistancePixelModel> zoomLevels;
private List<System.Drawing.Point> scaleLinePoints;
public MapScaleControllerView()
{
InitializeComponent();
var g = CreateGraphics();
var millimeterLength = NativeAPI.GetDeviceCaps(g.GetHdc(), NativeAPI.HORZSIZE);
var pixelLength = Screen.PrimaryScreen.Bounds.Width;
g.Dispose();
millimeterPerPixel = (double)millimeterLength / (double)pixelLength;
pixelPerMillimeter = (double)pixelLength / (double)millimeterLength;
Initialize();
}
private void Initialize()
{
var evtMgr = ModuleManager.GetInstance().GetEventManager();
var distances = new List<long>()
{
10,30,50,
100,300,500,
1000,3000,5000,
10000,20000,30000,50000,
100000,200000,300000,500000,
1000000,2000000,3000000,5000000,
10000000,30000000,50000000,
100000000,300000000,500000000,
1000000000,3000000000,5000000000,
};
var unites = new List<string>()
{
"1厘米","3厘米","5厘米",
"10厘米","30厘米","50厘米",
"1米","3米","5米",
"10米","20米","30米","50米",
"100米","200米","300米","500米",
"1公里","2公里","3公里","5公里",
"10公里","20公里","50公里",
"100公里","200公里","500公里",
"1000公里","2000公里","5000公里"
};
evtMgr.Subscribe(EventNames.MAP_MAIN_MAP_EXTENT_CHANGED, ViewNames.MAP_MAP_SCALE_CONTROL_VIEW, OnMainMapExtentChanged);
zoomLevels = new List<DistancePixelModel>();
for (var i = 0; i < distances.Count; i++)
{
zoomLevels.Add(new DistancePixelModel()
{
Distance = distances[i],
Level = distances.Count - i,
ScreenPixel = distances[i] * pixelPerMillimeter,
Unit = unites[i]
});
}
scaleLinePoints = new List<System.Drawing.Point>();
scaleLinePoints.Add(new System.Drawing.Point(10, 20));
scaleLinePoints.Add(new System.Drawing.Point(10, 30));
scaleLinePoints.Add(new System.Drawing.Point(190, 30));
scaleLinePoints.Add(new System.Drawing.Point(190, 20));
}
private void SetZoomLevel(MainMapControlView mapCtrl)
{
var centmeterPixel = pixelPerMillimeter * 10;
var c1 = mapCtrl.PixelToProj(new System.Drawing.Point(Convert.ToInt32(centmeterPixel), 0));
var c2 = mapCtrl.PixelToProj(new System.Drawing.Point(Convert.ToInt32(centmeterPixel * 2), 0));
var pc2 = new Coordinate(0, 0);
var p1 = mapCtrl.ProjToPixel(pc2);
var p2 = p1;
var centmeterDistance = (c2.X - c1.X) * 1000;
var scale = 1.0;
foreach (var level in zoomLevels)
{
scale = centmeterDistance / level.Distance;
if (scale < 1)
{
iZoomLevel = level.Level;
sDynamicScaleString = level.Unit;
pc2 = new Coordinate(level.Distance / 1000, 0);
break;
}
}
p2 = mapCtrl.ProjToPixel(pc2);
iScaleLineLength = p2.X - p1.X + 10;
scaleLinePoints[2] = new System.Drawing.Point(iScaleLineLength, 30);
scaleLinePoints[3] = new System.Drawing.Point(iScaleLineLength, 20);
}
private void UpdateZoomLevels(MainMapControlView mapCtrl)
{
var zeroPixel = mapCtrl.ProjToPixel(new Coordinate(0, 0));
var referenceCoordinate = new Coordinate(0, 0);
var referencePixel = zeroPixel;
foreach (var level in zoomLevels)
{
referenceCoordinate.X = level.Distance / 1000;
referencePixel = mapCtrl.ProjToPixel(referenceCoordinate);
level.MapPixel = referencePixel.X - zeroPixel.X;
}
}
private void OnMainMapExtentChanged(object obj)
{
var mapCtrl = ModuleManager.GetInstance().GetViewManager().GetView<IMainMapControlView>() as MainMapControlView;
var g = CreateGraphics();
UpdateZoomLevels(mapCtrl);
SetZoomLevel(mapCtrl);
if (InvokeRequired)
Invoke(new Action(() => DrawScale(g, mapCtrl)));
else
DrawScale(g, mapCtrl);
g.Dispose();
}
private void DrawScale(Graphics g, MainMapControlView mapCtrl)
{
var parentRectangle = mapCtrl.RectangleToClient(RectangleToScreen(ClientRectangle));
var path = new GraphicsPath();
var sf = new StringFormat(StringFormatFlags.NoWrap);
var ff = new FontFamily(GenericFontFamilies.SansSerif);
g.Clip = new Region(ClientRectangle);
g.DrawImage(mapCtrl.BufferedImage, -parentRectangle.Left, -parentRectangle.Top);
g.DrawLines(new Pen(Color.Black, 2), scaleLinePoints.ToArray());
g.DrawString(sDynamicScaleString, new Font("微软雅黑", 10), Brushes.Black, new PointF(12, 10));
}
protected override void OnPaint(PaintEventArgs e)
{
var mapCtrl = ModuleManager.GetInstance().GetViewManager().GetView<IMainMapControlView>() as MainMapControlView;
base.OnPaint(e);
UpdateZoomLevels(mapCtrl);
SetZoomLevel(mapCtrl);
DrawScale(e.Graphics, mapCtrl);
}
public int CurrentZoomLevel
{
get { return iZoomLevel; }
}
}
}