SharpMap学习10比例尺

看了SharpMap的比例尺相关代码,看的是一知半解,主要原因在于代码中的Zoom和以往对比例尺的概念联系不上,但是代码的意思,我想应该是一个坐标系(也就是地理坐标,或者叫WordView)到窗口坐标的转换吧。这个似乎在图形编程的时候经常用到,自己理解不是很深刻,那就将就着写点感悟吧。

地理坐标系下是笛卡尔坐标系

image 而屏幕坐标系:image

假设地理坐标系下,也就是现实中一个点如下左图示,要转为屏幕点(右侧图)显示,就需要通过比例转换得到:

image

具体转换公式很简单,分别处理X,Y即可。简单实践代码如下,首先定义一个显示的点集合:

public class Geometry
{
private List<PointF> points;
public List<PointF> Points
{
get
{
return points;
}
}

public Geometry()
{
this.points = new List<PointF>();
}

public void ReadData()
{
PointF pt;

pt = new PointF(13183368.7f, 3836485.263f);
points.Add(pt);

pt = new PointF(13183709.796f, 3785207.202f);
points.Add(pt);

pt = new PointF(13206335.814f, 3784297.613f);
points.Add(pt);

pt = new PointF(13210770.059f, 3802716.783f);
points.Add(pt);

pt = new PointF(13230667.311f, 3803398.975f);
points.Add(pt);

pt = new PointF(13231804.297f, 3820453.762f);
points.Add(pt);

pt = new PointF(13206790.608f, 3839327.727f);
points.Add(pt);
}

public Geometry Colon()
{
Geometry geometry = new Geometry();
foreach (PointF ptItem in this.points)
{
geometry.points.Add(ptItem);
}
return geometry;
}
}

然后类似定义一个Map对象

class Map
{
private int imgWidth;
private int imgHeight;

public int ImgWidth
{
get
{
return imgWidth;
}
set
{
imgWidth = value;
}
}

public int ImgHeight
{
get
{
return imgHeight;
}
set
{
imgHeight = value;
}
}

private float zoomScale;
public float ZoomScale
{
get
{
return zoomScale;
}
set
{
if (value < 1)
return;
zoomScale = value;
}
}

public Map(int imgWidth,int imgHeight)
{
this.imgWidth = imgWidth;
this.imgHeight = imgHeight;

this.zoomScale = 100.0f;

this.data = new Geometry();
data.ReadData();
}

private Geometry data = null;

public PointF GetCenter()
{
PointF resultPt = new PointF();
if (this.data != null)
{
BoundingBox box = Utility.GetEnvolope(this.data.Points);
resultPt.X = (box.MinX + box.MaxX) / 2.0f;
resultPt.Y = (box.MinY + box.MaxY) / 2.0f;
}
return resultPt;
}

public void GetLineMap(Graphics g)
{
Geometry lineGeo = data.Colon();
for (int i = 0; i < lineGeo.Points.Count; i++)
{
lineGeo.Points[i] = Utility.WordToImage(lineGeo.Points[i], this);
}

GraphicsPath gpPath = new GraphicsPath();
gpPath.AddLines(lineGeo.Points.ToArray());

g.DrawPath(linePen, gpPath);
}

public void GetRegionMap(Graphics g)
{
Geometry regionGeo = data.Colon();
for (int i = 0; i < regionGeo.Points.Count; i++)
{
regionGeo.Points[i] = Utility.WordToImage(regionGeo.Points[i], this);
}

GraphicsPath gpPath = new GraphicsPath();
gpPath.AddPolygon(regionGeo.Points.ToArray());

g.FillPath(regionBrush, gpPath);
}

private Pen linePen = new Pen(Color.Red, 3);
private Brush regionBrush = new SolidBrush(Color.FromArgb(120, Color.Blue));

public float GetExtentZoomScale()
{
if (this.data != null)
{
return Utility.GetEnvolope(this.data.Points).BoundingWidth;
}
else
{
return 0;
}
}
}

在绘制前,首先要遍历每一个点,将其从地理坐标转为窗口坐标,以下是具体的转换函数:

public static PointF WordToImage(PointF wordPt, Map map)
{
PointF imgPt = new PointF();
float wordHeight = map.ZoomScale * (float)map.ImgHeight / (float)map.ImgWidth;

float wordLeft = map.GetCenter().X - map.ZoomScale * 0.5f;
float wordTop = map.GetCenter().Y + wordHeight * 0.5f;

imgPt.X = (wordPt.X - wordLeft) / map.ZoomScale * map.ImgWidth;
imgPt.Y = (wordTop - wordPt.Y) / wordHeight * map.ImgHeight;

return imgPt;
}

解释下,Map对象的ZoomScale是作为“比例尺”的“比例”概念存在的,按照一些博文中的解释,是作为地理坐标显示范围的宽度处理的,也就是说地理显示范围(真实范围)的宽度=ZoomScale,通过它和窗口中高、宽比再求得地理显示范围的高,从而进行转换操作的。SharpMap中还涉及到其他的参数处理,不过我觉得大概意思应该是这样的吧。

最终效果:

image改变比例尺:image        image

原文地址:https://www.cnblogs.com/sharpfeng/p/2075553.html