1. SharpMap中屏幕坐标和地图Map坐标转换:

 using System.Drawing;
using GeoAPI.Geometries; namespace SharpMap.Utilities
{
/// <summary>
/// Class for transforming between world and image coordinate
/// </summary>
public class Transform
{
/// <summary>
/// Transforms from world coordinate system (WCS) to image coordinates
/// 将世界坐标转换为image坐标
/// NOTE: This method DOES NOT take the MapTransform property into account (use <see cref="Map.WorldToImage(GeoAPI.Geometries.Coordinate,bool)"/> instead)
/// </summary>
/// <param name="p">Point in WCS</param>
/// <param name="map">Map reference</param>
/// <returns>Point in image coordinates</returns>
public static PointF WorldtoMap(Coordinate p, Map map)
{
//if (map.MapTransform != null && !map.MapTransform.IsIdentity)
// map.MapTransform.TransformPoints(new System.Drawing.PointF[] { p });
if (p.IsEmpty())
return PointF.Empty; var result = new PointF(); var height = (map.Zoom * map.Size.Height) / map.Size.Width;
var left = map.Center.X - map.Zoom * 0.5;
var top = map.Center.Y + height * 0.5 * map.PixelAspectRatio;
result.X = (float)((p.X - left) / map.PixelWidth);
result.Y = (float)((top - p.Y) / map.PixelHeight);
if (double.IsNaN(result.X) || double.IsNaN(result.Y))
result = PointF.Empty;
return result;
} /// <summary>
/// Transforms from image coordinates to world coordinate system (WCS).
/// NOTE: This method DOES NOT take the MapTransform property into account (use <see cref="Map.ImageToWorld(System.Drawing.PointF,bool)"/> instead)
/// </summary>
/// <param name="p">Point in image coordinate system</param>
/// <param name="map">Map reference</param>
/// <returns>Point in WCS</returns>
public static Coordinate MapToWorld(PointF p, Map map)
{
if (map.Center.IsEmpty() || double.IsNaN(map.MapHeight))
{
return new Coordinate(, );
}
var ul = new Coordinate(map.Center.X - map.Zoom * ., map.Center.Y + map.MapHeight * .);
return new Coordinate(ul.X + p.X * map.PixelWidth,
ul.Y - p.Y * map.PixelHeight);
}
}
}

Transform

详细分析: http://www.cnblogs.com/yhlx125/archive/2012/02/10/2342282.html

2. OpenS-CAD中的实现

已知屏幕分辨率每英寸像素点数,一般为96dpi,  定义float m_screenResolution = 96;

1. 初始化CanvasCtrl时,首先调用OnResize()方法。

 protected override void OnResize(EventArgs e)
{
base.OnResize(e); if (m_lastCenterPoint != UnitPoint.Empty && Width != )
SetCenterScreen(ToScreen(m_lastCenterPoint), false);
m_lastCenterPoint = CenterPointUnit();
m_staticImage = null;
DoInvalidate(true);
}

OnResize

由于m_lastCenterPoint是结构体变量,所以首先设置到中心点m_lastCenterPoint,即(0,0),是Unit坐标

if (m_lastCenterPoint != UnitPoint.Empty && Width != 0)
    SetCenterScreen(ToScreen(m_lastCenterPoint), false);

接着调用m_lastCenterPoint = CenterPointUnit();

通过直角坐标的左上角点和右下角点计算。其实初始化时候执行该方法没有起到设置基准点的作用。可以跳过这2次,等窗体Resize的时候再看。

 public UnitPoint CenterPointUnit()
{
UnitPoint p1 = ScreenTopLeftToUnitPoint();
UnitPoint p2 = ScreenBottomRightToUnitPoint();
UnitPoint center = new UnitPoint();
center.X = (p1.X + p2.X) / ;
center.Y = (p1.Y + p2.Y) / ;
return center;
}
public UnitPoint ScreenTopLeftToUnitPoint()
{
return ToUnit(new PointF(, ));
}
public UnitPoint ScreenBottomRightToUnitPoint()
{
return ToUnit(new PointF(this.ClientRectangle.Width, this.ClientRectangle.Height));
}

CenterPointUnit

2. 接着打开文档DocumentForm,在构造的过程中设置文档画布的视点中心坐标为(0,0)。这样就实现了绘图画布原点坐标和屏幕(客户区)中心点的对应,形成基准点。默认的数据的长度单位为inch,屏幕坐标的单位为像素。这两者之间存在比例关系,通过Zoom缩放比例来实现尺度的变换,同时结合平移量和偏移距离计算出鼠标点的世界坐标。

m_canvas.SetCenter(new UnitPoint(0, 0));

或者加载完数据,设置画布的视点中心坐标。

m_canvas.SetCenter(m_data.CenterPoint);

 public DocumentForm(string filename)
{
InitializeComponent(); Text = "<New Document>";
m_data = new DataModel();
if (filename.Length > && File.Exists(filename) && m_data.Load(filename))
{
Text = filename;
m_filename = filename;
} m_canvas = new CanvasCtrl(this, m_data);
m_canvas.Dock = DockStyle.Fill;
Controls.Add(m_canvas);
m_canvas.SetCenter(new UnitPoint(, ));
m_canvas.RunningSnaps = new Type[]
{
typeof(VertextSnapPoint),
typeof(MidpointSnapPoint),
typeof(IntersectSnapPoint),
typeof(QuadrantSnapPoint),
typeof(CenterSnapPoint),
typeof(DivisionSnapPoint),
}; m_canvas.AddQuickSnapType(Keys.N, typeof(NearestSnapPoint));
m_canvas.AddQuickSnapType(Keys.M, typeof(MidpointSnapPoint));
m_canvas.AddQuickSnapType(Keys.I, typeof(IntersectSnapPoint));
m_canvas.AddQuickSnapType(Keys.V, typeof(VertextSnapPoint));
m_canvas.AddQuickSnapType(Keys.P, typeof(PerpendicularSnapPoint));
m_canvas.AddQuickSnapType(Keys.Q, typeof(QuadrantSnapPoint));
m_canvas.AddQuickSnapType(Keys.C, typeof(CenterSnapPoint));
m_canvas.AddQuickSnapType(Keys.T, typeof(TangentSnapPoint));
m_canvas.AddQuickSnapType(Keys.D, typeof(DivisionSnapPoint)); m_canvas.KeyDown += new KeyEventHandler(OnCanvasKeyDown);
SetupMenuItems();
SetupDrawTools();
SetupLayerToolstrip();
SetupEditTools();
UpdateLayerUI(); MenuStrip menuitem = new MenuStrip();//创建文档的主菜单
menuitem.Items.Add(m_menuItems.GetMenuStrip("edit"));
menuitem.Items.Add(m_menuItems.GetMenuStrip("draw"));
menuitem.Visible = false;
Controls.Add(menuitem);
this.MainMenuStrip = menuitem;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
m_canvas.SetCenter(m_data.CenterPoint);
}

  2.1查看SetCenter(UnitPoint unitPoint)方法,首先调用PointF point = ToScreen(unitPoint);将unitPoint转换PointF point.找到地图原点对应的屏幕坐标,应该是屏幕左下角点偏移(25,-25)。

         /// <summary>
/// 设置画布到屏幕的中心
/// </summary>
/// <param name="rPoint">直角坐标系坐标</param>
public void SetCenter(RPoint unitPoint)
{
//将unitPoint点对应到屏幕上point
PointF point = Transform.ToScreen(unitPoint, this);
m_lastCenterPoint = unitPoint;
//将unitPoint偏移到屏幕中心
SetCenterScreen(point, false);
}

SetCenter

 这里注意计算Unit坐标到屏幕坐标的ToScreen()方法中,transformedPoint.Y = ScreenHeight() - transformedPoint.Y;//将Unit坐标系转换为屏幕坐标系,Y轴反向

 其中ScreenHeight()方法似乎有点问题,修改后如下。

  /// <summary>
/// 将Unit坐标转换到屏幕坐标
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public PointF ToScreen(UnitPoint point)
{
PointF transformedPoint = Translate(point);
transformedPoint.Y = ScreenHeight() - transformedPoint.Y;//将Unit坐标系转换为屏幕坐标系,Y轴反向
transformedPoint.Y *= m_screenResolution * m_model.Zoom;
transformedPoint.X *= m_screenResolution * m_model.Zoom; transformedPoint.X += m_panOffset.X + m_dragOffset.X;
transformedPoint.Y += m_panOffset.Y + m_dragOffset.Y;
return transformedPoint;
}

ToScreen

 float ScreenHeight()
{
return (float)(ToUnit(this.ClientRectangle.Height));
//return (float)(ToUnit(this.ClientRectangle.Height) / m_model.Zoom);
}

ScreenHeight

   这样就引出了ToUnit(float screenvalue)函数,将屏幕距离转换为英寸数。

 public double ToUnit(float screenvalue)
{
return (double)screenvalue / (double)(m_screenResolution * m_model.Zoom);
}

3. 接着将unitPoint赋值给m_lastCenterPoint

m_lastCenterPoint = unitPoint;

SetCenterScreen(point, false);

调用了SetCenterScreen()方法,

 protected  void SetCenterScreen(PointF screenPoint, bool setCursor)
{
float centerX = ClientRectangle.Width / ;
m_panOffset.X += centerX - screenPoint.X; float centerY = ClientRectangle.Height / ;
m_panOffset.Y += centerY - screenPoint.Y; if (setCursor)
Cursor.Position = this.PointToScreen(new Point((int)centerX, (int)centerY));
DoInvalidate(true);
}

4.理解了public PointF ToScreen(UnitPoint point),那public UnitPoint ToUnit(PointF screenpoint)也好理解了。

  /// <summary>
/// 将屏幕坐标转换到Unit坐标
/// </summary>
/// <param name="screenpoint"></param>
/// <returns></returns>
public UnitPoint ToUnit(PointF screenpoint)
{
float panoffsetX = m_panOffset.X + m_dragOffset.X;
float panoffsetY = m_panOffset.Y + m_dragOffset.Y;
float xpos = (screenpoint.X - panoffsetX) / (m_screenResolution * m_model.Zoom);
float ypos = ScreenHeight() - ((screenpoint.Y - panoffsetY)) / (m_screenResolution * m_model.Zoom);
return new UnitPoint(xpos, ypos);
}

ToUnit

5.最后单独说一下ToScreen(UnitPoint point)和ToUnit(PointF screenpoint)中的两个变量

PointF m_panOffset = new PointF(, -);
PointF m_dragOffset = new PointF(, );

这里m_panOffset控制的是中心点Center的偏移量,是一个累计的量,相对于中心点。

m_dragOffset记录了每次移动过程中的移动量,每次产生一个新值。每次CanvasCtrl控件的OnMouseDown时累积到偏移量上,之后重新初始化,同时在OnMouseUp时的移动命令下重新初始化(如下代码),似乎重复了。

 if (m_commandType == eCommandType.pan)
{
m_panOffset.X += m_dragOffset.X;
m_panOffset.Y += m_dragOffset.Y;
m_dragOffset = new PointF(, );
}

在protected override void OnMouseMove(MouseEventArgs e)事件中

 if (m_commandType == eCommandType.pan && e.Button == MouseButtons.Left)
{
m_dragOffset.X = -(m_mousedownPoint.X - e.X);
m_dragOffset.Y = -(m_mousedownPoint.Y - e.Y);
m_lastCenterPoint = CenterPointUnit();
DoInvalidate(true);
}

可知,m_dragOffset和m_panOffset记录的是偏移的屏幕坐标。

[SharpMap] 屏幕坐标和Map坐标转换的更多相关文章

  1. PIE SDK屏幕坐标和地图坐标转换

    1. 功能简介 屏幕坐标和地图坐标转换,就是字面意思,将电脑屏幕的坐标转换为带有空间信息的地图坐标,主要运用PIE SDK地图控件的ToMapPoint()方法,而地图坐标转换为设备坐标(屏幕),用的 ...

  2. 分享:Unity3D模型跟随鼠标移动功能的小脚本 (屏幕坐标和三维空间坐标转换)

    using UnityEngine; using System.Collections; public class ModelsPosChange : MonoBehaviour { RaycastH ...

  3. C#+SharpMap的相关代码

    //放大的代码: private void MapZoomIn(NameValueCollection queryString) { SharpMap.Map map = Session[" ...

  4. 一步一步手写GIS开源项目-(1)500行代码实现基础GIS展示功能

    1.开篇 大学毕业工作已经两年了,上学那会就很想研读一份开源GIS的源码,苦于自己知识和理解有限,而市面上也没有什么由浅入深讲解开源gis原理的书籍,大多都是开源项目简介以及项目的简单应用.对于初级程 ...

  5. (十四)WebGIS中地图放大缩小的设计和实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 在上一章中,我们给出了整个工具栏设计的核心,使用命令模式,并 ...

  6. Unity经典游戏教程之:弓之骑士

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  7. svg 实践之屏幕坐标与svg元素坐标转换

    近期在做svg相关项目,很好用的东西要记下来: 1.基础知识就是根据 矩阵进行坐标转换,如下: : 屏幕坐标 = 矩阵* svg对象坐标 2.javascript有个方法用于获取 svg对象 的转换矩 ...

  8. 百度Map与HT for Web结合的GIS网络拓扑应用

    在<HT for Web整合OpenLayers实现GIS地图应用>篇中介绍了HT for Web与OpenLayers的整合,不少朋友反应国内用得比较多的还是百度地图,虽然HT整合百度地 ...

  9. C# SharpMap的简单使用

    本文是利用ShapMap实现GIS的简单应用的小例子,以供学习分享使用.关于SharpMap的说明,网上大多是以ShapeFile为例进行简单的说明,就连官网上的例子也不多.本文是自己参考了源代码进行 ...

随机推荐

  1. mybatis传递Map和List集合示例

    1.List示例 java文件: dao: public List<ServicePort> selectByIps(List<String> ips); xml文件: < ...

  2. TFS对签入文件忽略设置,解决pdb弹出警告

    我们在使用TFS项目老是出现冲突,要么编译的时候 提示PDB被签出这类的大量弹出,很烦人. 在群友的指点下,对签入文件进行限制.对PDB禁止签入以后,整个世界安静了.非常感谢 TFS=>服务器管 ...

  3. Leetcode: Best Time to Buy and Sell Stock I, II

    思路: 1. 算法导论讲 divide and conquer 时, 讲到过这个例子. 书中的做法是先让 price 数组减去一个值, 然后求解最大连续子数组的和. 分治算法的复杂度为 o(nlogn ...

  4. GIS-"地理空间大数据与AI的碰撞"学习笔记

    1.关系 人工智能>机器学习>神经网络>深度学习 2.机器学习-两个过程 训练/学习过程:样本数据.学习器.模型参数 测试/预测过程:预测.预测值 3.神经网络 机器学习模拟人脑神经 ...

  5. 为什么在js当中没有var就是全局变量

    因为,在js中,如果某个变量没有var声明,会自动移到上一层作用域中去找这个变量的声明语句,如果找到,就是用,如果没找到, 就继续向上寻找,一直查找到全局作用域为止,如果全局中仍然没有这个变量的声明语 ...

  6. 集群应用Session一致性实现的三种方案

    转自:http://blog.csdn.net/zwx521515/article/details/78679679 https://www.cnblogs.com/study-everyday/p/ ...

  7. 什么是"抓包"?怎样"抓包"?

    你是网络管理员吗?你是不是有过这样的经历:在某一天的早上你突然发现网络性能急剧下降,网络服务不能正常提供,服务器访问速度极慢甚至不能访问,网络交换机端口指示灯疯狂地闪烁.网络出口处的路由器已经处于满负 ...

  8. [置顶] 数据库优化实践【MS SQL优化开篇】

    数据库定义: 数据库是依照某种数据模型组织起来并存在二级存储器中的数据集合,此集合具有尽可能不重复,以最优方式为特定组织提供多种应用服务,其数据结构独立于应用程序,对数据的CRUD操作进行统一管理和控 ...

  9. pythonday

    python学习          http://www.cnblogs.com/fengyuhao/p/7168903.html pythonday    http://www.cnblogs.co ...

  10. 窗口大小改变绑定resize事件

    当为窗口绑定resize事件时,大部分浏览器会在每改变一个像素就触发一次resize事件.这严重影响了网站的性能. 解决方案是:利用settimeout方法为事件发触发的方法设置延迟执行的时间. 实现 ...