vectorrenderer.cs

来自「Sharp Map 用于制作GIS系统S harp Map 用于制作GIS系统S」· CS 代码 · 共 376 行

CS
376
字号
// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Collections.Generic;
using System.Text;

namespace SharpMap.Rendering
{
	/// <summary>
	/// This class renders individual geometry features to a graphics object using the settings of a map object.
	/// </summary>
	public class VectorRenderer
	{
		private static System.Drawing.Bitmap defaultsymbol = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SharpMap.Styles.DefaultSymbol.png"));

		/// <summary>
		/// Renders a MultiLineString to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="lines">MultiLineString to be rendered</param>
		/// <param name="pen">Pen style used for rendering</param>
		/// <param name="map">Map reference</param>
		public static void DrawMultiLineString(System.Drawing.Graphics g, Geometries.MultiLineString lines, System.Drawing.Pen pen, SharpMap.Map map)
		{
			for (int i = 0; i < lines.LineStrings.Count; i++)
				DrawLineString(g, lines.LineStrings[i], pen, map);
		}

		/// <summary>
		/// Renders a LineString to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="line">LineString to render</param>
		/// <param name="pen">Pen style used for rendering</param>
		/// <param name="map">Map reference</param>
		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);
			}
		}

		/// <summary>
		/// Renders a multipolygon byt rendering each polygon in the collection by calling DrawPolygon.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="pols">MultiPolygon to render</param>
		/// <param name="brush">Brush used for filling (null or transparent for no filling)</param>
		/// <param name="pen">Outline pen style (null if no outline)</param>
		/// <param name="clip">Specifies whether polygon clipping should be applied</param>
		/// <param name="map">Map reference</param>
		public static void DrawMultiPolygon(System.Drawing.Graphics g, Geometries.MultiPolygon pols, System.Drawing.Brush brush, System.Drawing.Pen pen, bool clip, SharpMap.Map map)
		{
			for (int i = 0; i < pols.Polygons.Count; i++)
				DrawPolygon(g, pols.Polygons[i], brush, pen, clip, map);
		}

		/// <summary>
		/// Renders a polygon to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="pol">Polygon to render</param>
		/// <param name="brush">Brush used for filling (null or transparent for no filling)</param>
		/// <param name="pen">Outline pen style (null if no outline)</param>
		/// <param name="clip">Specifies whether polygon clipping should be applied</param>
		/// <param name="map">Map reference</param>
		public static void DrawPolygon(System.Drawing.Graphics g, SharpMap.Geometries.Polygon pol, System.Drawing.Brush brush, System.Drawing.Pen pen, bool clip, SharpMap.Map map)
		{
			if (pol.ExteriorRing == null)
				return;
			if (pol.ExteriorRing.Vertices.Count > 2)
			{
				//Use a graphics path instead of DrawPolygon. DrawPolygon has a problem with several interior holes
				System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();

				//Add the exterior polygon
				if (!clip)
					gp.AddPolygon(pol.ExteriorRing.TransformToImage(map));
				else
					gp.AddPolygon(clipPolygon(pol.ExteriorRing.TransformToImage(map), map.Size.Width, map.Size.Height));

				//Add the interior polygons (holes)
				for (int i = 0; i < pol.InteriorRings.Count; i++)
					if (!clip)
						gp.AddPolygon(pol.InteriorRings[i].TransformToImage(map));
					else
						gp.AddPolygon(clipPolygon(pol.InteriorRings[i].TransformToImage(map), map.Size.Width, map.Size.Height));

				// Only render inside of polygon if the brush isn't null or isn't transparent
				if (brush != null && brush != System.Drawing.Brushes.Transparent)
					g.FillPath(brush, gp);
				// Create an outline if a pen style is available
				if (pen != null)
					g.DrawPath(pen, gp);
			}
		}

		/// <summary>
		/// Renders a label to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="LabelPoint">Label placement</param>
		/// <param name="Offset">Offset of label in screen coordinates</param>
		/// <param name="font">Font used for rendering</param>
		/// <param name="forecolor">Font forecolor</param>
		/// <param name="backcolor">Background color</param>
		/// <param name="halo">Color of halo</param>
		/// <param name="rotation">Text rotation in degrees</param>
		/// <param name="text">Text to render</param>
		/// <param name="map">Map reference</param>
		public static void DrawLabel(System.Drawing.Graphics g, System.Drawing.PointF LabelPoint, System.Drawing.PointF Offset, System.Drawing.Font font, System.Drawing.Color forecolor, System.Drawing.Brush backcolor, System.Drawing.Pen halo, float rotation, string text, SharpMap.Map map)
		{
			System.Drawing.SizeF fontSize = g.MeasureString(text, font); //Calculate the size of the text
			LabelPoint.X += Offset.X; LabelPoint.Y += Offset.Y; //add label offset
			if (rotation != 0 && rotation != float.NaN)
			{
				g.TranslateTransform(LabelPoint.X, LabelPoint.Y);
				g.RotateTransform(rotation);
				g.TranslateTransform(-fontSize.Width / 2, -fontSize.Height / 2);
				if (backcolor != null && backcolor != System.Drawing.Brushes.Transparent)
					g.FillRectangle(backcolor, 0, 0, fontSize.Width * 0.74f + 1f, fontSize.Height * 0.74f);
				System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
				path.AddString(text, font.FontFamily, (int)font.Style, font.Size, new System.Drawing.Point(0, 0), null);
				if (halo != null)
					g.DrawPath(halo, path);
				g.FillPath(new System.Drawing.SolidBrush(forecolor), path);
				//g.DrawString(text, font, new System.Drawing.SolidBrush(forecolor), 0, 0);				
				g.Transform = map.MapTransform;
			}
			else
			{
				if (backcolor != null && backcolor != System.Drawing.Brushes.Transparent)
					g.FillRectangle(backcolor, LabelPoint.X, LabelPoint.Y, fontSize.Width * 0.74f + 1, fontSize.Height * 0.74f);

				System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();

				path.AddString(text, font.FontFamily, (int)font.Style, font.Size, LabelPoint, null);
				if (halo != null)
					g.DrawPath(halo, path);
				g.FillPath(new System.Drawing.SolidBrush(forecolor), path);
				//g.DrawString(text, font, new System.Drawing.SolidBrush(forecolor), LabelPoint.X, LabelPoint.Y);
			}
		}
		/*private System.Drawing.RectangleF GetPathEnvelope(System.Drawing.Drawing2D.GraphicsPath gp)
		{
			float minX = float.MaxValue; float minY = float.MaxValue;
			float maxX = float.MinValue; float maxY = float.MinValue;
			for(int i=0;i<gp.PointCount;i++)
				if(minX>gp.PathPoints[i].X)
		}*/

		/// <summary>
		/// Clips a polygon to the view.
		/// Based on UMN Mapserver renderer [This method is currently not used. It seems faster just to draw the outside points as well)
		/// </summary>
		/// <param name="vertices">vertices in image coordinates</param>
		/// <param name="width">Width of map in image coordinates</param>
		/// <param name="height">Height of map in image coordinates</param>
		/// <returns>Clipped polygon</returns>
		internal static System.Drawing.PointF[] clipPolygon(System.Drawing.PointF[] vertices, int width, int height)
		{
			float deltax, deltay, xin, xout, yin, yout;
			float tinx, tiny, toutx, touty, tin1, tin2, tout;
			float x1, y1, x2, y2;

			List<System.Drawing.PointF> line = new List<System.Drawing.PointF>();
			if (vertices.Length <= 1) /* nothing to clip */
				return vertices;
			/*
			** Don't do any clip processing of shapes completely within the
			** clip rectangle based on a comparison of bounds.   We could do 
			** something similar for completely outside, but that rarely occurs
			** since the spatial query at the layer read level has generally already
			** discarded all shapes completely outside the rect.
			*/

			// TODO
			//if (vertices.bounds.maxx <= width
			//		&& vertices.bounds.minx >= 0
			//		&& vertices.bounds.maxy <= height
			//		&& vertices.bounds.miny >= 0)
			//	{
			//		return vertices;
			//	}


			//line.point = (pointObj*)malloc(sizeof(pointObj) * 2 * shape->line[j].numpoints + 1); /* worst case scenario, +1 allows us to duplicate the 1st and last point */
			//line.numpoints = 0;

			for (int i = 0; i < vertices.Length - 1; i++)
			{
				x1 = vertices[i].X;
				y1 = vertices[i].Y;
				x2 = vertices[i + 1].X;
				y2 = vertices[i + 1].Y;

				deltax = x2 - x1;
				if (deltax == 0)
				{	// bump off of the vertical
					deltax = (x1 > 0) ? -float.MinValue : float.MinValue;
				}
				deltay = y2 - y1;
				if (deltay == 0)
				{	// bump off of the horizontal
					deltay = (y1 > 0) ? -float.MinValue : float.MinValue;
				}

				if (deltax > 0)
				{   //  points to right
					xin = 0;
					xout = width;
				}
				else
				{
					xin = width;
					xout = 0;
				}

				if (deltay > 0)
				{   //  points up
					yin = 0;
					yout = height;
				}
				else
				{
					yin = height;
					yout = 0;
				}

				tinx = (xin - x1) / deltax;
				tiny = (yin - y1) / deltay;

				if (tinx < tiny)
				{   // hits x first
					tin1 = tinx;
					tin2 = tiny;
				}
				else
				{   // hits y first
					tin1 = tiny;
					tin2 = tinx;
				}

				if (1 >= tin1)
				{
					if (0 < tin1)
						line.Add(new System.Drawing.PointF(xin, yin));

					if (1 >= tin2)
					{
						toutx = (xout - x1) / deltax;
						touty = (yout - y1) / deltay;

						tout = (toutx < touty) ? toutx : touty;

						if (0 < tin2 || 0 < tout)
						{
							if (tin2 <= tout)
							{
								if (0 < tin2)
								{
									if (tinx > tiny)
										line.Add(new System.Drawing.PointF(xin, y1 + tinx * deltay));
									else
										line.Add(new System.Drawing.PointF(x1 + tiny * deltax, yin));
								}

								if (1 > tout)
								{
									if (toutx < touty)
										line.Add(new System.Drawing.PointF(xout, y1 + toutx * deltay));
									else
										line.Add(new System.Drawing.PointF(x1 + touty * deltax, yout));
								}
								else
									line.Add(new System.Drawing.PointF(x2, y2));
							}
							else
							{
								if (tinx > tiny)
									line.Add(new System.Drawing.PointF(xin, yout));
								else
									line.Add(new System.Drawing.PointF(xout, yin));
							}
						}
					}
				}
			}
			if (line.Count > 0)
				line.Add(new System.Drawing.PointF(line[0].Y, line[0].Y));

			return line.ToArray();
		}

		/// <summary>
		/// Renders a point to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="point">Point to render</param>
		/// <param name="symbol">Symbol to place over point</param>
		/// <param name="symbolscale">The amount that the symbol should be scaled. A scale of '1' equals to no scaling</param>
		/// <param name="offset">Symbol offset af scale=1</param>
		/// <param name="rotation">Symbol rotation in degrees</param>
		/// <param name="map">Map reference</param>
		public static void DrawPoint(System.Drawing.Graphics g, SharpMap.Geometries.Point point, System.Drawing.Bitmap symbol, float symbolscale, System.Drawing.PointF offset, float rotation, SharpMap.Map map)
		{
			if (point == null)
				return;
			if (symbol == null) //We have no point style - Use a default symbol
				symbol = defaultsymbol;
			System.Drawing.PointF pp = SharpMap.Utilities.Transform.WorldtoMap(point, map);

			if (rotation != 0 && rotation != float.NaN)
			{
				g.TranslateTransform(pp.X, pp.Y);
				g.RotateTransform(rotation);
				g.TranslateTransform(-symbol.Width / 2, -symbol.Height / 2);
				if (symbolscale == 1f)
					g.DrawImageUnscaled(symbol, (int)(pp.X - symbol.Width / 2 + offset.X), (int)(pp.Y - symbol.Height / 2 + offset.Y));
				else
				{
					float width = symbol.Width * symbolscale;
					float height = symbol.Height * symbolscale;
					g.DrawImage(symbol, (int)pp.X - width / 2 + offset.X * symbolscale, (int)pp.Y - height / 2 + offset.Y * symbolscale, width, height);
				}
				g.Transform = map.MapTransform;
			}
			else
			{
				if (symbolscale == 1f)
					g.DrawImageUnscaled(symbol, (int)(pp.X - symbol.Width / 2 + offset.X), (int)(pp.Y - symbol.Height / 2 + offset.Y));
				else
				{
					float width = symbol.Width * symbolscale;
					float height = symbol.Height * symbolscale;
					g.DrawImage(symbol, (int)pp.X - width / 2 + offset.X * symbolscale, (int)pp.Y - height / 2 + offset.Y * symbolscale, width, height);
				}
			}
		}

		/// <summary>
		/// Renders a <see cref="SharpMap.Geometries.MultiPoint"/> to the map.
		/// </summary>
		/// <param name="g">Graphics reference</param>
		/// <param name="points">MultiPoint to render</param>
		/// <param name="symbol">Symbol to place over point</param>
		/// <param name="symbolscale">The amount that the symbol should be scaled. A scale of '1' equals to no scaling</param>
		/// <param name="offset">Symbol offset af scale=1</param>
		/// <param name="rotation">Symbol rotation in degrees</param>
		/// <param name="map">Map reference</param>
		public static void DrawMultiPoint(System.Drawing.Graphics g, Geometries.MultiPoint points, System.Drawing.Bitmap symbol, float symbolscale, System.Drawing.PointF offset, float rotation, SharpMap.Map map)
		{
			for (int i = 0; i < points.Points.Count; i++)
				DrawPoint(g, points.Points[i], symbol, symbolscale, offset, rotation, map);
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?