⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mifreader.cs

📁 实现SHP
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.IO;
using System.Text.RegularExpressions;

using GeoCon.Data;
using gml;
 
namespace GeoCon.mif
{
	/// <summary>
	/// Reader for MapInfo mif/mid file.
	/// </summary>
	public class MifReader
	{

		/// <summary>
		/// Occurs when there's noticable change in this reader progress.
		/// </summary>
		public event GeoCon.Data.StatusEventHandler StatusChange;
		private GeoCon.Data.StatusEventArgs StatusArgs = new GeoCon.Data.StatusEventArgs("",0); 

		#region private constants
		private const string TYPE_NONE = "none";
		private const string TYPE_POINT = "point";
		private const string TYPE_LINE = "line";
		private const string TYPE_PLINE = "pline";
		private const string TYPE_REGION = "region";
		private const string TYPE_ARC = "arc";
		private const string TYPE_TEXT = "text";
		private const string TYPE_RECT = "rect";
		private const string TYPE_RECT2 = "rectangle";
		private const string TYPE_ROUNDRECT = "roundrect";
		private const string TYPE_ROUNDRECT2 = "rounded";
		private const string TYPE_ELLIPSE = "ellipse";

		private const string CLAUSE_SYMBOL = "SYMBOL";
		private const string CLAUSE_PEN = "PEN";
		private const string CLAUSE_SMOOTH= "SMOOTH";
		private const string CLAUSE_CENTER = "CENTER";
		private const string CLAUSE_BRUSH = "BRUSH";

		private const string CLAUSE_VERSION = "VERSION";
		private const string CLAUSE_CHARSET = "CHARSET";
		private const string CLAUSE_DELIMETER = "DELIMITER";
		private const string CLAUSE_COORDSYS = "COORDSYS";
		private const string CLAUSE_UNIQUE = "UNIQUE";
		private const string CLAUSE_INDEX = "INDEX";
		private const string CLAUSE_COLUMNS = "COLUMNS";
		#endregion

		#region private fields
		private System.IO.StreamReader fReader;
		private System.IO.StreamReader mReader;
		private string name;
		//private string defaultsrs="http://www.opengis.net/gml/srs/epsg.xml#4326";
		private string defaultsrs=" ";
		private bool hasBBox=false; //whether bounding box supplied in mif file
		private mif.FeatureHeader fHeader;
		private util.StringTokenizer tokenizer = new util.StringTokenizer("");
		#endregion

		#region constructor & public methods
		/// <summary>
		/// Construct new MifReader.
		/// </summary>
		/// <param name="mifpath">path to the mif file.</param>
		public MifReader(string mifpath)
		{
			try
			{
				fHeader = new FeatureHeader();

				System.IO.Stream fstream = new FileStream(mifpath,FileMode.Open,FileAccess.Read,FileShare.Read);
				fReader = new StreamReader(fstream);

				string fne =System.IO.Path.GetFileNameWithoutExtension(mifpath);
				name=fne;
				string midpath = fne + ".mid";
				if(File.Exists(midpath)) 
				{
					System.IO.Stream dstream = new FileStream(midpath,FileMode.Open,FileAccess.Read,FileShare.Read);
					mReader = new StreamReader(dstream);
				}
			}
			catch (System.IO.FileNotFoundException fnfe)
			{
				//System.Windows.Forms.MessageBox.Show("file '"+fnfe.FileName+"' not found.");
				throw new FileNotFoundException("MifReader : "+fnfe.FileName + " not found.\n" + fnfe.Message); 
			}
			catch(System.Exception ioe)
			{
				//System.Windows.Forms.MessageBox.Show("error : \r"+ioe.Message);
				throw new Exception("MifReader : "+ioe.Message,ioe.InnerException);   
			}
		}


		/// <summary>
		/// Starts reading shape and data
		/// </summary>
		/// <returns>new MapData which holds the mif/mid data.</returns>
		public MapData Read()
		{
			UpdateStatus("reading "+name+"..",0);

			//initializing box values, in case bounding box not supplied by mif file;
			fHeader.coordSys.left  = double.MaxValue; 
			fHeader.coordSys.top   = -double.MaxValue;
			fHeader.coordSys.right = -double.MaxValue;
			fHeader.coordSys.bottom= double.MaxValue;

			MapData mapdata = new MapData();
			mapdata.Name=name;

			ReadHeader(ref mapdata);
			ReadData(ref mapdata);

			mapdata.Info.FileDirectory = System.Environment.CurrentDirectory;//  System.IO.Path.GetDirectoryName(name);
			mapdata.Info.FileVersion = fHeader.version.ToString();
			mapdata.Info.FileGeometry  = name+".mif";
			mapdata.Info.FileData = (mReader!=null)? name+".mid" : "not found";
			mapdata.Info.RecordsCount = mapdata.Fields[0].Count; 
			mapdata.Info.ProjectionName = fHeader.coordSys.Name; 
			mapdata.Info.BoundsLeft=fHeader.coordSys.left;
			mapdata.Info.BoundsTop=fHeader.coordSys.top;
			mapdata.Info.BoundsRight=fHeader.coordSys.right;
			mapdata.Info.BoundsBottom=fHeader.coordSys.bottom;
			
			mapdata.BoundingBox=new gml.BoxType(fHeader.coordSys.left,fHeader.coordSys.top,fHeader.coordSys.right,fHeader.coordSys.bottom);

			UpdateStatus("Finished reading "+name,0);
			return mapdata;
		}

		/// <summary>
		/// close the reader/stream associated with this reader. Plus some clean up.
		/// </summary>
		public void Close()
		{
			fReader.Close();
			if(mReader!=null) mReader.Close();

			name=null;
			defaultsrs=null;
			tokenizer=null;
		}
		#endregion

		#region header stuff
		/// <summary>
		/// Read mif header information.
		/// </summary>
		/// <param name="mapdata">MapData into which the data will be stored</param>
		private void ReadHeader(ref MapData mapdata)
		{
			//onStatusChange(new GeoCon.Util.StatusEventArgs("reading header..",0));

			string[] uniques=new string[0]; //unique columns indexes
			string[] indexes=new string[0]; //indexed columns indexes

			string token="";
			util.StringTokenizer stoken = new util.StringTokenizer(" ");
			while(fReader.Peek()>=0)
			{
				stoken.str=fReader.ReadLine();
				stoken.reset();
				if(stoken.hasMoreTokens()) token=stoken.nextToken();
				if(token.ToUpper()=="DATA") break;
				switch (token.ToUpper())
				{
					case CLAUSE_VERSION :
						if(stoken.hasMoreTokens()) fHeader.version=double.Parse(stoken.nextToken().Trim());
						break;
					case CLAUSE_CHARSET :
						if(stoken.hasMoreTokens()) fHeader.charset=stoken.nextToken().Trim(new char[1]{'"'});
						break;
					case CLAUSE_DELIMETER :	//delimiter for data in mid file
						if(stoken.hasMoreTokens()) fHeader.delimiter=stoken.nextToken().Trim(new char[1]{'"'});
						break;
					case CLAUSE_COORDSYS :
						stoken.str=stoken.str.Replace(fHeader.delimiter+" ", fHeader.delimiter);
						ReadCoordSys(stoken);				
						break;
					case CLAUSE_UNIQUE :
						if(stoken.hasMoreTokens()) uniques=stoken.nextToken().Trim().Split(fHeader.delimiter.ToCharArray());
						break;
					case CLAUSE_INDEX :
						if(stoken.hasMoreTokens()) indexes=stoken.nextToken().Trim().Split(fHeader.delimiter.ToCharArray());
						break;			
					case CLAUSE_COLUMNS :
						//onStatusChange(new util.StatusEventArgs("reading columns..",0));
						int count=0;
						if(stoken.hasMoreTokens()) count = Convert.ToInt32(stoken.nextToken());
						ReadColumnHeader(ref mapdata,count);
						break;
					default:
						// unknown/empty line identifier
						break;
				}
			}
			token=null;
			stoken=null;

			for(int i=0;i<uniques.Length;i++)
			{
				int fi=int.Parse(uniques[i])-1;
				mapdata.Fields[fi].isUnique=true;
			}
			for(int i=0;i<indexes.Length;i++)
			{
				int fi=int.Parse(indexes[i])-1;
				mapdata.Fields[fi].isIndex=true;
			}
			uniques=null;
			indexes=null;
		}
		
		/// <summary>
		/// Reads column information in a mif file.
		/// </summary>
		/// <param name="mapdata">MapData where the column info will be stored</param>
		/// <param name="count">number of columns to read</param>
		private void ReadColumnHeader(ref MapData mapdata,int count)
		{
			Field f;
			string tp="";
			//util.StringTokenizer st=new util.StringTokenizer(""," (),\0".ToCharArray());
			util.StringTokenizer st=new util.StringTokenizer(""," ,()\0".ToCharArray());
			for (int i=0;i<count;i++)								  
			{	
				st.reset();
				st.str=fReader.ReadLine();
				if(mReader==null) continue;
				mapdata.Info.FieldsCount+=1;
				string fname="";
				if(st.hasMoreTokens()) fname = st.nextToken();
				if(st.hasMoreTokens()) tp = st.nextToken();
				switch (tp.ToLower())
				{
					case "char":
						f = st.hasMoreTokens()? new StringField(int.Parse(st.nextToken())) : new StringField();
						break;
					case "integer":
						f=new IntegerField();
						break;
					case "smallint":
						f=new IntegerField();
						break;
					case "float":
						f=new DoubleField();
						break;
					case "decimal":
						f=new DoubleField(int.Parse(st.nextToken()),int.Parse(st.nextToken()));
						break;
					case "date":
						f=new DateTimeField();
						break;
					case "logical":
						f=new BoolField();
						break;
					default :
						f = new StringField();
						break;
				}
				f.Name = fname;
				mapdata.Fields.Add(f);
			}
			f=null;
			st=null;
			//mapdata.Info.FieldsCount = count;
		}
		#endregion

		#region read data stuff
		/// <summary>
		/// Reads geometry & non-geometry data.
		/// </summary>
		/// <param name="mapdata">MapData into where the data will be stored</param>
		private void ReadData(ref MapData mapdata)
		{
			int curcount=0;

			GeometryField fgeo=new Data.GeometryField();
			string fpartType="";
			while(fReader.Peek()>=0)
			{
				curcount+=1;
				if(curcount>=99) curcount=0;
				UpdateStatus("",curcount);

				tokenizer.reset();
				tokenizer.str = fReader.ReadLine();
				tokenizer.delimiters =new char[1]{' '};
				if(tokenizer.hasMoreTokens()) fpartType=tokenizer.nextToken();
				switch (fpartType.ToLower())
				{
					case TYPE_NONE :
						ReadFeatureNone(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_POINT :
						ReadFeaturePoint(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_LINE :
						ReadFeatureLine(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_PLINE :
						ReadFeaturePLine(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_REGION :
						ReadFeatureRegion(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_ARC :
						ReadFeatureArc(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_TEXT :
						ReadFeatureText(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_RECT :
						ReadFeatureRect(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_RECT2 : //older version of rectangle
						ReadFeatureRect(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_ROUNDRECT :
						ReadFeatureRoundRect(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_ROUNDRECT2 : //older version of rounded rectangle
						ReadFeatureRoundRect(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					case TYPE_ELLIPSE :
						ReadFeatureEllipse(ref fgeo);
						ReadFeatureData(ref mapdata);
						break;
					default: 
						curcount-=1;
						//check if this is style data
						if(isShadingClause(tokenizer.str)) ReadFeatureStyle(tokenizer.str);
						break;
				}
			}
			mapdata.Fields.Add(fgeo);
		}
		#endregion

		#region read geometry stuff
		/// <summary>
		/// Read null shape geometry.
		/// </summary>
		/// <param name="fgeo">The GeometryField where the new feature will be added to</param>
		private void ReadFeatureNone(ref GeometryField fgeo)
		{
			fgeo.Add(fgeo.NullSymbol);
		}
		/// <summary>
		/// Read feature text
		/// </summary>
		/// <param name="fgeo">The GeometryField where the new feature will be stored</param>
		private void ReadFeatureText(ref GeometryField fgeo)
		{
			//consider this rect as the text background rectangle :)
			fReader.ReadLine(); //skip one line -> this is the text value;
			tokenizer.reset();
			tokenizer.str=fReader.ReadLine(); //this is the bounding box
			ReadFeatureRect(ref fgeo);
		}
		/// <summary>
		/// Read Arc
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeatureArc(ref GeometryField fgeo)
		{
			//i know i should turn arcs into polylines, but why bother?
			//i'd rather have other people do the conversion using mapinfo
			ReadFeatureRect(ref fgeo);
		}
		/// <summary>
		/// Read Ellipse
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeatureEllipse(ref GeometryField fgeo)
		{
			//idem
			ReadFeatureRect(ref fgeo);
		}
		/// <summary>
		/// Read Rounded Rectangle
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeatureRoundRect(ref GeometryField fgeo)
		{
			ReadFeatureRect(ref fgeo);
			//just the rectangle.
		}
		/// <summary>
		/// Read Rectangle
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeatureRect(ref GeometryField fgeo)
		{
			double left = double.Parse(tokenizer.nextToken());
			double bottom = double.Parse(tokenizer.nextToken());
			double right = double.Parse(tokenizer.nextToken());
			double top = double.Parse(tokenizer.nextToken());
			//update bbox
			if(hasBBox==false) updateBoundingBox(left,top,right,bottom);
			double[] da=new double[8]{left,bottom, left,top, right,top, right,bottom};
			gml.PolygonType _pt=new PolygonType(new gml.CoordinatesType(da));
			fgeo.Add(new gml.PolygonPropertyType(_pt));
			da=null;
		}
		/// <summary>
		/// Read point
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeaturePoint(ref GeometryField fgeo)
		{
			int tt=-1;
			double[] da=new double[2];
			while(tokenizer.hasMoreTokens()) 
			{
				tt++;
				da[tt] = double.Parse(tokenizer.nextToken());
				if(tt>1) break;
			}
			if(hasBBox==false) updateBoundingBox(da[0],da[1],da[0],da[1]);
			gml.PointType _pt = new gml.PointType(new gml.CoordinatesType(da));
			fgeo.Add(new gml.PointPropertyType(_pt));
			da=null;
			_pt=null;
		}
		/// <summary>
		/// Read Line
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeatureLine(ref GeometryField fgeo)
		{
			double[] da=new double[4];
			int tt=-1;
			while(tokenizer.hasMoreTokens()) 
			{
				tt++;
				da[tt] = double.Parse(tokenizer.nextToken());
				if(tt>3) break;
			}
			if(hasBBox==false) 
			{
				updateBoundingBox(da[0],da[1],da[2],da[3]);
				updateBoundingBox(da[2],da[3],da[0],da[1]);
			}
			gml.LineStringType _ls = new gml.LineStringType(new gml.CoordinatesType(da));
			fgeo.Add(new gml.LineStringPropertyType(_ls));
			da  = null;
			_ls = null;
		}
		/// <summary>
		/// Reads Polyline
		/// </summary>
		/// <param name="fgeo">The GeometryField to store the new gml type</param>
		private void ReadFeaturePLine(ref GeometryField fgeo)
		{
			string token = tokenizer.nextToken();
			if(token.ToLower()=="multiple")
			{
				int partsNum=int.Parse(tokenizer.nextToken());
				gml.LineStringType[] LSArray = new gml.LineStringType[partsNum]; 
				for(int j=0;j<partsNum;j++)
				{
					int tuplesNum = int.Parse(fReader.ReadLine());
					LSArray[j]    = new gml.LineStringType(new gml.CoordinatesType(ReadCoordinates(tuplesNum)));
				}

				gml.MultiLineStringType _mls = new gml.MultiLineStringType(defaultsrs,LSArray);
				fgeo.Add(new gml.MultiLineStringPropertyType(_mls));
				_mls=null;
				LSArray=null;

⌨️ 快捷键说明

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