sharpmap 也看了一段时间了 0.9是一个很好的地图渲染组件 闲话少说
先看例子:
SharpMap.Map myMap = new SharpMap.Map(picMap.Size); SharpMap.Layers.VectorLayer myLayer = new SharpMap.Layers.VectorLayer("My layer"); ... ... myMap.Layers.Add(myLayer); myMap.Center = new SharpMap.Geometries.Point(725000, 6180000); myMap.Zoom = 1200; myMap.Size = new System.Drawing.Size(300,200); System.Drawing.Image imgMap = myMap.GetMap(); //Renders the map
渲染流程
1.设置map类的Zoom和Center坐标 可以得到地图当前视图的bbox即Envlope
public SharpMap.Geometries.BoundingBox Envelope { get { return new SharpMap.Geometries.BoundingBox( new SharpMap.Geometries.Point(this.Center.X - this.Zoom * .5, this.Center.Y - this.MapHeight * .5), new SharpMap.Geometries.Point(this.Center.X + this.Zoom * .5, this.Center.Y + this.MapHeight * .5)); } }
其中Zoom为当前窗口对应实际的地图宽度MapWidth(Map类没有这属性,但有MapHeight,一般的地图缩放都是以Width为基准,height根据width算出)
这样上面算法就比较好理解了,最小坐标(左下)与最大坐标(右上)注意:地图坐标X坐标轴向右,Y坐标轴向上,与屏幕坐标方向不一致,其Y坐标轴向下。
MapHeight Zoom 乘以 高宽比和像素高宽比(默认为1.0)
public double MapHeight { get { return (this.Zoom * this.Size.Height) / this.Size.Width * this.PixelAspectRatio; } }
2.map调用GetMap函数进行渲染(渲染到Size大小的Image上) ,GetMap里面首先设置Graphics的Transform为地图Map的MapTransform(坐标变换矩阵用于进行平面坐标变换如平移变换,比例变换,对称变换,旋转变换,错切变换或者复合变换)然后主要调用各个Layers的Render函数,代码如下:
public System.Drawing.Image GetMap() { if (Layers == null || Layers.Count == 0) throw new InvalidOperationException("No layers to render"); System.Drawing.Image img = new System.Drawing.Bitmap(this.Size.Width, this.Size.Height); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(img); g.Transform = this.MapTransform; g.Clear(this.BackColor); g.PageUnit = System.Drawing.GraphicsUnit.Pixel; int SRID = (Layers.Count > 0 ? Layers[0].SRID : -1); //Get the SRID of the first layer for (int i = 0; i < _Layers.Count; i++) { if (_Layers[i].Enabled && _Layers[i].MaxVisible >= this.Zoom && _Layers[i].MinVisible < this.Zoom) _Layers[i].Render(g, this); } if (MapRendered != null) MapRendered(g); //Fire render event g.Dispose(); return img; }
3.VectorLayer.Render函数里面通过envelop查询数据源得到视图内几何数据集合(IDataSource.ExecuteIntersectionQuery函数),如果需要利用不同于数据的坐标系显示地图则需要坐标转换(设置CoordinateTransformation),则对每个几何对象进行坐标转换,如果是生成专题图即设置了theme,对每个几何对象渲染时利用theme获取其style,如果是普通地图即theme为null,则使用默认style,然后调用RenderGeometry方法渲染每个几何对象。代码如下:
public override void Render(System.Drawing.Graphics g, Map map) { if (map.Center == null) throw (new ApplicationException("Cannot render map. View center not specified")); g.SmoothingMode = this.SmoothingMode; SharpMap.Geometries.BoundingBox envelope = map.Envelope; //View to render if (this.CoordinateTransformation != null) envelope = SharpMap.CoordinateSystems.Transformations.GeometryTransform.TransformBox(envelope, this.CoordinateTransformation.MathTransform.Inverse()); //List features = this.DataSource.GetGeometriesInView(map.Envelope); if (this.DataSource == null) throw (new ApplicationException("DataSource property not set on layer '" + this.LayerName + "'")); //If thematics is enabled, we use a slighty different rendering approach if (this.Theme != null) { SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet(); this.DataSource.Open(); this.DataSource.ExecuteIntersectionQuery(envelope, ds); this.DataSource.Close(); SharpMap.Data.FeatureDataTable features = (SharpMap.Data.FeatureDataTable)ds.Tables[0]; if (this.CoordinateTransformation != null) for (int i = 0; i < features.Count; i++) features[i].Geometry = SharpMap.CoordinateSystems.Transformations.GeometryTransform.TransformGeometry(features[i].Geometry, this.CoordinateTransformation.MathTransform); //Linestring outlines is drawn by drawing the layer once with a thicker line //before drawing the "inline" on top. if (Style.EnableOutline) { //foreach (SharpMap.Geometries.Geometry feature in features) for (int i = 0; i < features.Count; i++) { SharpMap.Data.FeatureDataRow feature = features[i]; //Draw background of all line-outlines first if(feature.Geometry is SharpMap.Geometries.LineString) { SharpMap.Styles.VectorStyle outlinestyle1 = this.Theme.GetStyle(feature) as SharpMap.Styles.VectorStyle; if (outlinestyle1.Enabled && outlinestyle1.EnableOutline) SharpMap.Rendering.VectorRenderer.DrawLineString(g, feature.Geometry as LineString, outlinestyle1.Outline, map); } else if(feature.Geometry is SharpMap.Geometries.MultiLineString) { SharpMap.Styles.VectorStyle outlinestyle2 = this.Theme.GetStyle(feature) as SharpMap.Styles.VectorStyle; if (outlinestyle2.Enabled && outlinestyle2.EnableOutline) SharpMap.Rendering.VectorRenderer.DrawMultiLineString(g, feature.Geometry as MultiLineString, outlinestyle2.Outline, map); } } } for(int i=0;i geoms = this.DataSource.GetGeometriesInView(envelope); this.DataSource.Close(); if (this.CoordinateTransformation != null) for (int i = 0; i < geoms.Count; i++) geoms[i] = SharpMap.CoordinateSystems.Transformations.GeometryTransform.TransformGeometry(geoms[i], this.CoordinateTransformation.MathTransform); //Linestring outlines is drawn by drawing the layer once with a thicker line //before drawing the "inline" on top. if (this.Style.EnableOutline) { foreach (SharpMap.Geometries.Geometry geom in geoms) { if (geom != null) { //Draw background of all line-outlines first switch (geom.GetType().FullName) { case "SharpMap.Geometries.LineString": SharpMap.Rendering.VectorRenderer.DrawLineString(g, geom as LineString, this.Style.Outline, map); break; case "SharpMap.Geometries.MultiLineString": SharpMap.Rendering.VectorRenderer.DrawMultiLineString(g, geom as MultiLineString, this.Style.Outline, map); break; default: break; } } } } for (int i = 0; i < geoms.Count; i++) { if(geoms[i]!=null) RenderGeometry(g, map, geoms[i], this.Style); } } base.Render(g, map); }
4.RenderGeometry方法根据几何对象的类型(点线面等)调用VectorRenderer对象的DrawXX函数进行渲染
private void RenderGeometry(System.Drawing.Graphics g, Map map, Geometry feature, SharpMap.Styles.VectorStyle style) { switch (feature.GetType().FullName) { case "SharpMap.Geometries.Polygon": if (style.EnableOutline) SharpMap.Rendering.VectorRenderer.DrawPolygon(g, (Polygon)feature, style.Fill, style.Outline, _ClippingEnabled, map); else SharpMap.Rendering.VectorRenderer.DrawPolygon(g, (Polygon)feature, style.Fill, null, _ClippingEnabled, map); break; case "SharpMap.Geometries.MultiPolygon": if (style.EnableOutline) SharpMap.Rendering.VectorRenderer.DrawMultiPolygon(g, (MultiPolygon)feature, style.Fill, style.Outline, _ClippingEnabled, map); else SharpMap.Rendering.VectorRenderer.DrawMultiPolygon(g, (MultiPolygon)feature, style.Fill, null, _ClippingEnabled, map); break; case "SharpMap.Geometries.LineString": SharpMap.Rendering.VectorRenderer.DrawLineString(g, (LineString)feature, style.Line, map); break; case "SharpMap.Geometries.MultiLineString": SharpMap.Rendering.VectorRenderer.DrawMultiLineString(g, (MultiLineString)feature, style.Line, map); break; case "SharpMap.Geometries.Point": SharpMap.Rendering.VectorRenderer.DrawPoint(g, (Point)feature, style.Symbol, style.SymbolScale, style.SymbolOffset, style.SymbolRotation, map); break; case "SharpMap.Geometries.MultiPoint": SharpMap.Rendering.VectorRenderer.DrawMultiPoint(g, (MultiPoint)feature, style.Symbol, style.SymbolScale, style.SymbolOffset, style.SymbolRotation, map); break; case "SharpMap.Geometries.GeometryCollection": foreach(Geometries.Geometry geom in (GeometryCollection)feature) RenderGeometry(g, map, geom, style); break; default: break; } }
5.VectorRenderer.DrawXX实际上利用了GDI+接口的Graphic.DrawXX 画图 比如:
public static void DrawLineString(System.Drawing.Graphics g, Geometries.LineString line, System.Drawing.Pen pen, SharpMap.Map map) { if (line.Vertices.Count > 1) { System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath(); gp.AddLines(line.TransformToImage(map)); g.DrawPath(pen, gp); } }