在单位实习期间用sharpmap开源库写了一些小的程序,之后一些群友问怎么实现实时输入坐标,使得某个图层能够实时运动。我的解决方案比较简单就是每次动态输入坐标时刷新地图,在刷新之前要给动态图层传入新的坐标,然后控制地图显示的中心(map.center)和宽度(map.zoom),这里需要注意的是mapbox通过这两个属性控制视图范围,其中zoom对应的是显示宽度,但是不需要去设置map.height,因为height属性是根据zoom自动计算的,然后就是调用Mapbox.Refresh()。那么问题来了,怎么让图层不停的每次刷新单个坐标就是问题的关键,在sharpmap已有的图层labellayer和vectorlayer的数据源都是通过Iprovider这个接口实现的,而这个接口只能是一次输入的所有数据都被刷新了,而且关键问题是一般动态图层我们是符合自己业务逻辑的图标,这个图标完全没办法放进去,所以我们只能是自定义一个新的图层类。
自定义的类customlayer只需要实Ilayer这个接口就可以了,在这个接口下有一个Envlope属性是一定要实现的,如果每次传入的只是一个点来控制一个图标的移动,那么这里可以返回一个有点构成的Envlope,这个也是可以接受的,我一开始都是retrun null,虽然语法上是可以通过的,但是在之后的视图控制中就很容易出错,这是一点经验之谈,少走一点弯路。那么重点来了怎么按自己的需求绘制customlayer的图层,这个主要是通过Render(Graphics g,Map map)这个方法下面实现的,在这里你可以调用map下一个坐标转换方法wordtomap,把现实世界的坐标转换为g上的绘图坐标,然后就可以调用Graphics下的绘图方法绘制各种图形了,包括你的图标,最后记得加上base.refresh()。这个时候就可以像VectorLayer一样添加到你的mapbox里刷新了。之前写了一个很小的demo,回头找找可以发上来相互交流学习一下。
关于动态图层其他实现方法的思考:1、可不可以利用原有的图层实现:如果只是一个图片,可以像绘制专题图一样用vetorlayer,更改点的显示图标,但是问题是这个图标只能更改大小,方向什么的没办法控制了(默认是个红色圆,什么方向都一样)2、能不能不要每次都刷新整个map,效率有点低:目前来看比较麻烦,之前我有个思路是把动态图层绘制之前的图片保存下来,然后在customlayer中用过定时器之类的东西定时刷新,这样的话可以省去其他图层的重复绘制,但是图形跟新完需要传入mapbox时又需要一个刷新,单独一个图层类好像解决不了,大家有什么好的建议可以指点我一下。
(就这些吧,第一篇技术文档主要是把自己的一些心得体会记录一下鼓励自己继续进步,也希望一些志同道合的朋友一起交流)
附上我的主要代码,能执行的Demo我已上传了,需要的可以搜一下:
class Car: Layer
{
private IPoint _postion;
private double width;
public double Width
{
get { return width; }
set { width = value; }
}
private double high;
public double High
{
get { return high; }
set { high = value; }
}
public IPoint Postion
{
get { return _postion; }
set { _postion = value; }
}
/// <summary>
/// 无实际意义,只是为了完成虚构成员
/// </summary>
public override Envelope Envelope
{
get
{
return new Envelope(_postion.X, _postion.X, _postion.Y, _postion.Y);
}
}
/// <summary>
/// 绘制图层内容
/// </summary>
/// <param name="g"></param>
/// <param name="map"></param>
public override void Render(Graphics g, SharpMap.Map map)
{
if (Postion.Coordinate != null)
{
PointF[] p_coordinates3 = new PointF[3];
float w;
float h;
w = (float)(Width / map.PixelSize);
h = (float)(High / map.PixelSize);
PointF imagepostion = map.WorldToImage(Postion.Coordinate);
RectangleF regf = new RectangleF(imagepostion.X, imagepostion.Y, w, h);
//Rectangle reg = new Rectangle((int)imagepostion.X, (int)imagepostion.Y, 20, 30);
Pen p = new Pen(Color.Red);
Brush b = new SolidBrush(Color.Red);
g.FillRectangle(b, regf);
}
base.Render(g, map);
}