www.pudn.com > mitab-1.5.1.zip > MiWrapper.cs


// $Id: MiWrapper.cs,v 1.2 2005/03/24 17:02:06 dmorissette Exp $ 
// 
 
using System; 
using System.Runtime.InteropServices; 
using System.IO; 
using System.Collections; 
using System.Text; 
 
namespace EBop.MapObjects.MapInfo { 
 
	/* 
	 * These classes wrap the mitab c api functions to produce a hierarchy of classes giving readonly  
	 * access to the feature points. 
	 *  
	 * Requires mitab.dll (www.maptools.org) 
	 * See http://mitab.maptools.org/ 
	 *  
	 * Graham Sims, 
	 * Environment Bay of Plenty, Whakatane, New Zealand 
	 * http://www.envbop.govt.nz		 
	 */ 
 
	///  
	/// This is a helper class for our standard enumerator based on EnumImpl. Implementataions  
	/// (Features, Parts, Fields and Vertices) are array like structures that can provide 
	/// an object at a given index between 0 and Count  - 1. 
	///  
	interface IObjectProvider { 
		int Count { 
			get; 
		} 
		object GetObj(int idx); 
	} 
 
	///  
	/// Implementation of an enumeration scheme over an index (array like) structure.  
	/// This class provides an enumerator that will work over any IObjectProvider implementation 
	/// (Features, Parts, Fields and Vertices). 
	///  
	///  
	/// Calls to the GetEnumerator method of Fields, Parts and Vertices will return 
	/// an instance of this class. Calls to GetEnumerator of Features will return a descendant 
	/// of this class (due to the fact that features don't necessarily have a sequential 
	/// index). 
	///  
	public class IndexedEnum : IEnumerator { 
		public readonly int Count; 
		protected int eIdx = -1; 
		private readonly IObjectProvider objProvider; 
 
		internal IndexedEnum(IObjectProvider objProvider) { 
			this.objProvider = objProvider; 
		} 
 
		public virtual void Reset() { 
			eIdx = -1; 
		} 
 
		public object Current { 
			get { 
				return objProvider.GetObj(eIdx); 
			} 
		} 
 
		public virtual bool MoveNext() { 
			return (++eIdx < objProvider.Count); 
		} 
	} 
 
	///  
	/// Partial implementation of IEnumerable over an indexed (aray like) structure. 
	///  
	///  
	/// Fields, Vertices, Parts and Features all descend from this class. It serves to 
	/// provide the common functionality required to generate their enumerators. 
	///  
	public abstract class EnumImpl : IEnumerable, IObjectProvider { 
		public readonly int count; 
 
		protected EnumImpl(int count) { 
			this.count = count; 
		} 
 
		public int Count { 
			get { 
				return count; 
			} 
		} 
 
		public virtual IEnumerator GetEnumerator() { 
			return new IndexedEnum(this); 
		} 
 
		public abstract object GetObj(int idx); 
	} 
 
 
	///  
	/// Represents a readonly view of field in a layer. 
	///  
	///  
	/// A field instance does not relate explicity to a single feature instance. Rather 
	/// it represents all the features in the layer. To find the value of a field for a particular 
	/// feature one of the GetValueAs methods should be called, passing the feature in. 
	///  
	public class Field { 
		///  
		/// The field name 
		///  
		public readonly string Name; 
		///  
		/// The field type 
		///  
		public FieldType Type; 
		///  
		/// The index of the field within the layers set of fields. 
		///  
		public readonly int Index; 
		///  
		/// The field width 
		///  
		public readonly int Width; 
		///  
		/// The field precision 
		///  
		public readonly short Precision; 
		///  
		/// The layer this field belongs to. 
		///  
		public readonly Layer Layer; 
 
		protected internal Field(Layer layer, int i) { 
			this.Layer = layer; 
			this.Index = i; 
			this.Name = MiApi.mitab_c_get_field_name(layer.Handle, i); 
			this.Type = MiApi.mitab_c_get_field_type(layer.Handle, i); 
			this.Precision = (short) MiApi.mitab_c_get_field_precision(layer.Handle, i); 
			this.Width = MiApi.mitab_c_get_field_width(layer.Handle, i); 
		} 
 
		///  
		/// Returns a string representation of this fields value for the given feature. 
		///  
		/// The feature to find the fields value for. 
		/// A string representation of this fields value for the given feature 
		public string GetValueAsString(Feature feature) { 
			return MiApi.mitab_c_get_field_as_string(feature.Handle, this.Index); 
		} 
 
		///  
		/// Returns a double representation of this fields value for the given feature. 
		///  
		/// The feature to find the fields value for. 
		/// A double representation of this fields value for the given feature 
		public double GetValueAsDouble(Feature feature) { 
			return MiApi.mitab_c_get_field_as_double(feature.Handle, this.Index); 
		} 
 
		public override string ToString() { 
			return this.Name+", "+this.Type; 
		} 
 
	} 
 
	///  
	/// Contains the set of fields belonging to a layer. 
	///  
	///  
	/// This class descends EnumImpl, meaning the fields in the 
	/// set can be iterated using foreach. 
	/// It also has an index property allowing any field between 0 and Fields.Count-1 
	/// to be accessed directly with Fields[idx] 
	///  
	public class Fields : EnumImpl { 
		private Field[] fields; 
 
		protected internal Fields(Layer layer):base(MiApi.mitab_c_get_field_count(layer.Handle)) { 
			fields = new Field[Count]; 
			for (int i=0; i 
		/// Override this to support descendants of the Field class. 
		///  
		/// A Field, with the given index, belonging to the given Layer 
		protected internal virtual Field CreateField(Layer layer, int index) { 
			return new Field(layer, index); 
		} 
 
		public virtual Field this[int index] { 
			get { 
				return index < Count ? fields[index] : null; 
			} 
		} 
 
		public override object GetObj(int idx) { 
			return this[idx]; 
		} 
 
		public override string ToString() { 
			StringBuilder str = new StringBuilder(); 
			str.Append("Columns:\n"); 
			foreach (Field field in this) 
				str.Append(field.ToString()+"\t"); 
			return str.ToString(); 
		} 
	} 
 
 
	///  
	/// Represents a single vertex with an X,Y point in geometric space. 
	///  
	///  
	/// This is the base building block of a feature 
	///  
	public class Vertex { 
		public readonly double X,Y; 
		protected internal Vertex(double x, double y) { 
			this.X = x; 
			this.Y = y; 
		} 
		 
		public override string ToString() { 
			return this.X+", "+this.Y; 
		} 
	} 
 
	///  
	/// Contains the set of Vertices belonging to a single Part. 
	///  
	///  
	/// This class descends EnumImpl, meaning the vertices in the 
	/// set can be iterated using foreach. 
	/// It also has an index property allowing any vertice between 0 and Vertices.Count-1 
	/// to be accessed directly with Vertices[idx] 
	///  
	public class Vertices : EnumImpl { 
		public readonly Part Part; 
 
		protected internal Vertices(Part part): 
			base(MiApi.mitab_c_get_vertex_count(part.Feature.Handle, part.Index)) { 
			this.Part = part; 
		} 
 
		///  
		/// Override this to support descendants of the Vertex class. 
		///  
		/// A vertex with the given X,Y coordinates 
		protected internal virtual Vertex CreateVertex(double x, double y) { 
			return new Vertex(x ,y); 
		} 
 
		public virtual Vertex this[int index] { 
			get { 
				return index < Count ? CreateVertex( 
					MiApi.mitab_c_get_vertex_x(Part.Feature.Handle, Part.Index, index), 
					MiApi.mitab_c_get_vertex_y(Part.Feature.Handle, Part.Index, index)) : null; 
			} 
		} 
 
		public override object GetObj(int idx) { 
			return this[idx]; 
		} 
		 
		public override string ToString() { 
			StringBuilder str = new StringBuilder(); 
			foreach (Vertex v in this) 
				str.Append(v+"\t"); 
			return str.ToString(); 
		} 
	} 
 
	///  
	/// Represents a Part. 
	///  
	/// A feature will contain one or more parts. 
	public class Part { 
		public readonly Feature Feature; 
		public readonly Vertices Vertices; 
		public readonly int Index; 
 
		protected internal Part(Feature feature, int partIdx) { 
			this.Index = partIdx; 
			this.Feature = feature; 
			this.Vertices = CreateVertices(this); 
		} 
 
		///  
		/// Override this to support descendants of the Vertices class. 
		///  
		/// This parts vertices. 
		protected internal virtual Vertices CreateVertices(Part part) { 
			return new Vertices(this); 
		} 
 
		public override string ToString() { 
			return "Part: "+Index+"\nVertices:\n"+this.Vertices.ToString(); 
		} 
 
	} 
 
	///  
	/// Contains the set of Parts belonging to a single Feature. 
	///  
	/// This class descends EnumImple, meaning the Parts in the 
	/// set can be iterated using foreach. 
	/// It also has an index property allowing any Part between 0 and Parts.Count-1 
	/// to be accessed directly with Parts[idx] 
	///  
	public class Parts :  EnumImpl { 
		///  
		/// The feature these parts belong to. 
		///  
		public readonly Feature Feature; 
 
		protected internal Parts(Feature feature):base(MiApi.mitab_c_get_parts(feature.Handle)) { 
			this.Feature = feature; 
		} 
 
		///  
		/// Override this to support descendants of the Part class. 
		///  
		/// A part with the given index 
		protected internal virtual Part CreatePart(int partIdx) { 
			return new Part(this.Feature, partIdx); 
		} 
 
		public Part this[int index] { 
			get { 
				return index < Count ? CreatePart(index) : null; 
			} 
		} 
 
 
		public override object GetObj(int idx) { 
			return this[idx]; 
		} 
 
		public override string ToString() { 
			StringBuilder str = new StringBuilder(); 
			str.Append("Part Count: "+this.Count+"\n"); 
			foreach (Part part in this)  
				str.Append(part.ToString()+"\n"); 
			return str.ToString(); 
		} 
 
	} 
 
	///  
	/// Represents a single feature beloning to a layer. 
	///  
	public class Feature : IDisposable { 
		///  
		/// Handle used to manipulate the object in the C API. 
		///  
		public readonly IntPtr Handle; 
		///  
		/// The id of this feature. 
		///  
		public readonly int Id; 
		///  
		/// The feature type. 
		///  
		public readonly FeatureType Type; 
		///  
		/// The layer the Feature belongs to. 
		///  
		public readonly Layer Layer; 
		///  
		/// The set of parts comprising this feature. 
		///  
		public readonly Parts Parts; 
 
		protected internal Feature(Layer layer, int featureId) { 
			this.Id = featureId; 
			this.Layer = layer; 
			this.Handle = MiApi.mitab_c_read_feature(layer.Handle, featureId); 
			this.Type = MiApi.mitab_c_get_type(Handle); 
			this.Parts = CreateParts(this); 
		} 
 
		///  
		/// Override this to support descendants of the Parts class. 
		///  
		/// This layers fields 
		protected internal virtual Parts CreateParts(Feature feature) { 
			return new Parts(this); 
		} 
 
		///  
		/// Returns text associated with this feature 
		///  
		/// This will return an empty string, unless this features type is 
		/// TABFC_Text. 
		public string Text { 
			get { 
				return (this.Type == FeatureType.TABFC_Text) ? 
                    MiApi.mitab_c_get_text(this.Handle) : 
					""; 
			} 
		} 
 
		public override string ToString() { 
			StringBuilder str = new StringBuilder(); 
			str.Append("Feature: "+Id+"\nFields:\n"); 
 
			foreach (Field field in this.Layer.Fields) 
				str.Append(field.GetValueAsString(this).Trim()+"\t"); 
 
			str.Append("\n"+this.Parts.ToString()); 
 
			return str.ToString(); 
		} 
 
		///  
		/// Convenience method to return the next Feature in the file. 
		///  
		/// A following feature in the file. 
		public Feature GetNext() { 
			return new Feature(this.Layer, MiApi.mitab_c_next_feature_id(Layer.Handle, this.Id)); 
		} 
 
		private bool disposed = false; 
 
		public void Dispose(bool disposing) { 
			if (disposing && !disposed) { 
				MiApi.mitab_c_destroy_feature(this.Handle); 
				disposed = true; 
			} 
		} 
 
		public void Dispose() { 
			Dispose(true); 
		} 
 
		~Feature() { 
			Dispose(false); 
		} 
	} 
 
	///  
	/// Unlike the other enumerators. The feature id set isn't guaranteed to be sequential.  
	/// So we override the default seqeuntial iterator. 
	///  
	internal class FeaturesEnum : IndexedEnum { 
 
		private readonly Layer layer; 
 
		internal FeaturesEnum(IObjectProvider objProvider, Layer layer) : base(objProvider) { 
			this.layer = layer; 
		} 
 
		public override bool MoveNext() { 
			return (eIdx = MiApi.mitab_c_next_feature_id(layer.Handle, eIdx)) != -1; 
		} 
	} 
 
	///  
	/// Contains the set of features belonging to a single layer. 
	///  
	/// This class descends EnumImpl, meaning the features in the 
	/// set can be iterated using foreach. 
	/// It also has an index property allowing any feature between 0 and Features.Count-1 
	/// to be accessed directly with Features[idx] 
	public class Features : EnumImpl { 
		///  
		/// The layer the features belong to 
		///  
		public readonly Layer Layer; 
 
		protected internal Features(Layer layer) :  
			base(MiApi.mitab_c_get_feature_count(layer.Handle)) { 
			this.Layer = layer; 
		} 
 
		///  
		/// Override this to support descendants of the Feature class. 
		///  
		/// This layers fields 
		protected internal virtual Feature CreateFeature(int index) { 
			return new Feature(this.Layer, index); 
		} 
 
		public Feature this[int index] { 
			get { 
				return (index != -1) ? CreateFeature(index) : null; 
			} 
		} 
 
		public Feature GetFirst() { 
			return this[MiApi.mitab_c_next_feature_id(Layer.Handle, -1)]; 
		} 
 
		public override object GetObj(int idx) { 
			return this[idx]; 
		} 
 
		public override IEnumerator GetEnumerator() { 
			return new FeaturesEnum(this, Layer); 
		} 
 
		public override string ToString() { 
			StringBuilder str = new StringBuilder(); 
			str.Append("Feature Count: "+this.Count+"\n"); 
			foreach (Feature feature in this)  
				str.Append(feature.ToString()+"\n"); 
			return str.ToString(); 
		} 
 
	} 
 
	public class Layer { 
		///  
		/// Handle used to manipulate the object in the C API 
		///  
		public readonly IntPtr Handle; 
		public readonly Fields Fields; 
		public readonly Features Features; 
		public readonly string FileName; 
 
		protected internal Layer(string fileName) { 
			this.Handle = MiApi.mitab_c_open(fileName); 
			if (this.Handle == IntPtr.Zero) 
				throw new FileNotFoundException("File "+fileName+" not found", fileName); 
			this.Fields = CreateFields(); 
			this.Features = CreateFeatures(); 
			this.FileName = fileName; 
		} 
 
		///  
		/// Override this to support descendants of the Fields class. 
		///  
		/// This layers fields 
		protected internal virtual Fields CreateFields() { 
			return new Fields(this); 
		} 
 
		///  
		/// Override this to support descendants of the Feature class. 
		///  
		/// This layers features 
		protected internal virtual Features CreateFeatures() { 
			return new Features(this); 
		} 
 
		///  
		/// Factory method to return the layer with a given name. 
		///  
		///  
		///  
		public static Layer GetByName(string tabFileName) { 
			return new Layer(tabFileName); 
		} 
 
		public override string ToString() { 
			return "Layer: "+this.FileName; 
		} 
 
		///  
		/// Writes this layers features to the given textwriter 
		///  
		/// Destintation for the layers features 
		public void ToText(TextWriter writer) { 
			writer.WriteLine(this); 
			writer.WriteLine(this.Fields+"\n"); 
			writer.WriteLine(this.Features); 
		} 
 
		///  
		/// Writes this layers features as a text file. 
		///  
		/// The name of the file that will be created. 
		public void ToText(string fileName) { 
			ToText(new StreamWriter(fileName)); 
		} 
	} 
}