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));
}
}
}