public void TestMultipatchConversionWithMultipleRings() { Rectangular[] positions = new Rectangular[] { new Rectangular(0.0, 5.0), new Rectangular(5.0, 10.0), new Rectangular(10.0, 5.0), new Rectangular(5.0, 0.0), new Rectangular(0.0, 5.0), new Rectangular(2.0, 5.0), new Rectangular(5.0, 2.0), new Rectangular(8.0, 5.0), new Rectangular(5.0, 8.0), new Rectangular(2.0, 5.0), }; CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0); int[] parts = new int[] { 0, 5 }; MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.Ring, MultiPatchPartType.Ring }; double[] zValues = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures); MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue); patch.Write(); string result = m_stringWriter.ToString(); Regex polygonPattern = new Regex(m_polygonPattern); Assert.AreEqual(2, polygonPattern.Matches(result).Count); }
public void TestMultipatchConversionWithTriangleStrip() { Rectangular[] positions = new Rectangular[] { new Rectangular(0.0, 0.0), new Rectangular(0.0, 1.0), new Rectangular(1.0, 0.0), new Rectangular(1.0, 1.0), new Rectangular(2.0, 0.0), new Rectangular(2.0, 1.0), new Rectangular(3.0, 0.0) }; CartographicExtent extent = new CartographicExtent(0.0, 0.0, 3.0, 1.0); int[] parts = new int[] { 0 }; MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.TriangleStrip }; double[] zValues = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures); MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue); patch.Write(); string result = m_stringWriter.ToString(); Regex trianglePattern = new Regex(m_trianglePattern); Assert.AreEqual(5, trianglePattern.Matches(result).Count); }
public void TestMultipatchConversionWithInnerAndOuterRings() { Rectangular[] positions = new Rectangular[] { new Rectangular(0.0, 5.0), new Rectangular(5.0, 10.0), new Rectangular(10.0, 5.0), new Rectangular(5.0, 0.0), new Rectangular(0.0, 5.0), new Rectangular(2.0, 5.0), new Rectangular(5.0, 2.0), new Rectangular(8.0, 5.0), new Rectangular(5.0, 8.0), new Rectangular(2.0, 5.0), }; CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0); int[] parts = new int[] { 0, 5 }; MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.OuterRing, MultiPatchPartType.InnerRing }; double[] zValues = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures); MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue); patch.Write(); string result = m_stringWriter.ToString(); Assert.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(result, m_polygonPattern)); }
/// <summary> /// Writes the MultiPatch shape to its <see cref="CzmlDocument"/> as a series of polygon packets. /// </summary> public override void Write() { MultiPatchShape multipatch = (MultiPatchShape)m_shape; List <Polygon> polygons = new List <Polygon>(); StringDictionary metadata = new StringDictionary(); var fields = multipatch.GetMetadataFields(); foreach (String field in fields) { metadata.Add(field, multipatch.GetMetadataValue(field)); } for (int i = 0; i < multipatch.Count; i++) { List <ShapePart> polygonParts = new List <ShapePart>(); PolygonShape temp; switch (multipatch.GetPartType(i)) { case MultiPatchPartType.TriangleFan: case MultiPatchPartType.TriangleStrip: for (int j = 2; j < multipatch[i].Count; j++) { int firstIndex = (multipatch.GetPartType(i) == MultiPatchPartType.TriangleFan) ? 0 : j - 2; Cartographic[] vertices = new Cartographic[] { multipatch[i][firstIndex], multipatch[i][j - 1], multipatch[i][j] }; ShapePart triangle = new ShapePart(vertices, 0, vertices.Length); PolygonShape p = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, new ShapePart[] { triangle }); (new Polygon(p, m_document, m_color)).Write(); } break; case MultiPatchPartType.Ring: while (i < multipatch.Count && multipatch.GetPartType(i) == MultiPatchPartType.Ring) { temp = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, new ShapePart[] { multipatch[i] }); (new Polygon(temp, m_document, m_color)).Write(); i++; } i--; break; case MultiPatchPartType.OuterRing: case MultiPatchPartType.FirstRing: polygonParts.Add(multipatch[i]); MultiPatchPartType comparisonType = (multipatch.GetPartType(i) == MultiPatchPartType.OuterRing) ? MultiPatchPartType.InnerRing : MultiPatchPartType.Ring; while (++i < multipatch.Count && multipatch.GetPartType(i) == comparisonType) { polygonParts.Add(multipatch[i]); } temp = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, polygonParts.ToArray()); (new Polygon(temp, m_document, m_color)).Write(); i--; break; } } }
public MultiPatchShape( int recordNumber, StringDictionary metadata, CartographicExtent extent, int[] parts, MultiPatchPartType[] partTypes, Rectangular[] positions, double minimumZ, double maximumZ, double[] zValues, double minimumMeasure, double maximumMeasure, double[] measures, ShapeType shapeType = ShapeType.MultiPatch) : base(recordNumber, metadata, shapeType) { _extent = new CartographicExtent( extent.WestLongitude * Constants.RadiansPerDegree, extent.SouthLatitude * Constants.RadiansPerDegree, extent.EastLongitude * Constants.RadiansPerDegree, extent.NorthLatitude * Constants.RadiansPerDegree); _minimumZ = minimumZ; _maximumZ = maximumZ; _minimumMeasure = minimumMeasure; _maximumMeasure = maximumMeasure; _measures = (double[])measures.Clone(); for (int i = 0; i < positions.Length; i++) { positions[i] = new Rectangular(positions[i].X * Constants.RadiansPerDegree, positions[i].Y * Constants.RadiansPerDegree); } _parts = new ShapePart[parts.Length]; for (int i = 0; i < parts.Length; ++i) { int count = ((i == parts.Length - 1) ? positions.Length : parts[i + 1]) - parts[i]; _parts[i] = new ShapePart(positions, zValues, parts[i], count); } _partTypes = (MultiPatchPartType[])partTypes.Clone(); }
public ShapefileReader(string filename) { // ESRI Shapefile Technical Description: // http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { // File Header: // // Position Field Value Type Byte Order // -------- ----- ----- ---- ---------- // Byte 0 File Code 9994 Integer Big // Byte 4 Unused 0 Integer Big // Byte 8 Unused 0 Integer Big // Byte 12 Unused 0 Integer Big // Byte 16 Unused 0 Integer Big // Byte 20 Unused 0 Integer Big // Byte 24 File Length File Length Integer Big // Byte 28 Version 1000 Integer Little // Byte 32 Shape Type Shape Type Integer Little // Byte 36 Bounding Box Xmin Double Little // Byte 44 Bounding Box Ymin Double Little // Byte 52 Bounding Box Xmax Double Little // Byte 60 Bounding Box Ymax Double Little // Byte 68* Bounding Box Zmin Double Little // Byte 76* Bounding Box Zmax Double Little // Byte 84* Bounding Box Mmin Double Little // Byte 92* Bounding Box Mmax Double Little // // * Unused, with value 0.0, if not Measured or Z type byte[] fileHeader = Read(fs, _fileHeaderLength); if (fileHeader == null) { throw new InvalidDataException("Could not read shapefile header."); } _byteOrder = BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian; int fileCode = ToInteger(fileHeader, 0, ByteOrder.BigEndian);; if (fileCode != _fileCode) { throw new InvalidDataException("Could not read shapefile file code. Is this a valid shapefile?"); } int fileLengthInBytes = ToInteger(fileHeader, 24, ByteOrder.BigEndian) * 2; int version = ToInteger(fileHeader, 28, ByteOrder.LittleEndian); if (version != _version) { throw new InvalidDataException("Shapefile version " + version + " is not supported. Only version " + _version + " is supported."); } // If a .prj file exists, check to see if the projection is supported. string prjFilepath = Path.ChangeExtension(filename, "prj"); if (File.Exists(prjFilepath)) { string prj = System.IO.File.ReadAllText(prjFilepath); string projection = @"PROJECTION"; string unit = @"Degree"; if (Regex.IsMatch(prj, projection)) { throw new InvalidDataException("Shapefile projection not supported."); } else if (!(Regex.IsMatch(prj, unit))) { throw new InvalidDataException("Shapefile units not supported. Only degrees is supported."); } } _shapeType = (ShapeType)ToInteger(fileHeader, 32, ByteOrder.LittleEndian); double xMin = ToDouble(fileHeader, 36, ByteOrder.LittleEndian); double yMin = ToDouble(fileHeader, 44, ByteOrder.LittleEndian); double xMax = ToDouble(fileHeader, 52, ByteOrder.LittleEndian); double yMax = ToDouble(fileHeader, 60, ByteOrder.LittleEndian); if (fileLengthInBytes == _fileHeaderLength) { // If the shapefile is empty (that is, has no records), // the values for xMin, yMin, xMax, and yMax are unspecified. // // I like zero better. xMin = 0.0; yMin = 0.0; xMax = 0.0; yMax = 0.0; } _extent = new CartographicExtent(xMin, yMin, xMax, yMax); // Read each header... // Record Header: // // Position Field Value Type Byte Order // -------- ----- ----- ---- ---------- // Byte 0 Record Number Record Number Integer Big // Byte 4 Content Length Content Length Integer Big _shapes = new List <Shape>(); byte[] recordHeader; string dBaseFilepath = Path.ChangeExtension(filename, "dbf"); DataTable metadataTable = ParseDBF.ReadDBF(dBaseFilepath); while ((recordHeader = Read(fs, _recordHeaderLength)) != null) { int recordNumber = ToInteger(recordHeader, 0, ByteOrder.BigEndian); int contextLengthInBytes = ToInteger(recordHeader, 4, ByteOrder.BigEndian) * 2; byte[] record = Read(fs, contextLengthInBytes); int mOffset, zOffset; StringDictionary metadata = new StringDictionary(); foreach (DataColumn column in metadataTable.Columns) { metadata.Add(column.ColumnName, Convert.ToString(metadataTable.Rows[recordNumber - 1][column]).Trim()); } ShapeType recordShapeType = (ShapeType)ToInteger(record, 0, ByteOrder.LittleEndian); switch (recordShapeType) { case ShapeType.NullShape: // Filter out null shapes. Otherwise, every client // would have to deal with them. break; case ShapeType.Point: double x = ToDouble(record, 4, ByteOrder.LittleEndian); double y = ToDouble(record, 12, ByteOrder.LittleEndian); Cartographic position = new Cartographic(x, y, 0.0); _shapes.Add(new PointShape(recordNumber, metadata, position)); break; case ShapeType.PointM: x = ToDouble(record, 4, ByteOrder.LittleEndian); y = ToDouble(record, 12, ByteOrder.LittleEndian); position = new Cartographic(x, y, 0.0); double measure = ToDouble(record, 20, ByteOrder.LittleEndian); _shapes.Add(new PointMShape(recordNumber, metadata, position, measure)); break; case ShapeType.PointZ: x = ToDouble(record, 4, ByteOrder.LittleEndian); y = ToDouble(record, 12, ByteOrder.LittleEndian); double z = ToDouble(record, 20, ByteOrder.LittleEndian); position = new Cartographic(x, y, z); measure = ToDouble(record, 28, ByteOrder.LittleEndian); _shapes.Add(new PointZShape(recordNumber, metadata, position, measure)); break; case ShapeType.MultiPoint: case ShapeType.MultiPointM: case ShapeType.MultiPointZ: CartographicExtent extent = new CartographicExtent( ToDouble(record, 4, ByteOrder.LittleEndian), ToDouble(record, 12, ByteOrder.LittleEndian), ToDouble(record, 20, ByteOrder.LittleEndian), ToDouble(record, 28, ByteOrder.LittleEndian)); int numberOfPoints = ToInteger(record, 36, ByteOrder.LittleEndian); Cartographic[] points = new Cartographic[numberOfPoints]; for (int i = 0; i < numberOfPoints; ++i) { points[i] = new Cartographic( ToDouble(record, 40 + (16 * i), ByteOrder.LittleEndian), ToDouble(record, 40 + (16 * i) + 8, ByteOrder.LittleEndian), 0.0); } if (recordShapeType == ShapeType.MultiPoint) { _shapes.Add(new MultiPointShape(recordNumber, metadata, extent, points)); } else { mOffset = 40 + (16 * numberOfPoints); zOffset = 40 + (16 * numberOfPoints); if (recordShapeType == ShapeType.MultiPointZ) { mOffset = zOffset + 16 + (8 * numberOfPoints); } double mMin = ToDouble(record, mOffset, ByteOrder.LittleEndian); double mMax = ToDouble(record, mOffset + 8, ByteOrder.LittleEndian); double[] measures = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { measures[i] = ToDouble(record, mOffset + 16 + (8 * i), ByteOrder.LittleEndian); } if (recordShapeType == ShapeType.MultiPointM) { _shapes.Add(new MultiPointMShape(recordNumber, metadata, extent, points, mMin, mMax, measures)); } else { double zMin = ToDouble(record, zOffset, ByteOrder.LittleEndian); double zMax = ToDouble(record, zOffset + 8, ByteOrder.LittleEndian); double[] zValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { x = points[i].Longitude; y = points[i].Latitude; z = ToDouble(record, zOffset + 16 + (8 * i), ByteOrder.LittleEndian); points[i] = new Cartographic(x, y, z); } _shapes.Add(new MultiPointZShape(recordNumber, metadata, extent, points, zMin, zMax, mMin, mMax, measures)); } } break; case ShapeType.Polyline: case ShapeType.PolylineM: case ShapeType.PolylineZ: case ShapeType.Polygon: case ShapeType.PolygonM: case ShapeType.PolygonZ: case ShapeType.MultiPatch: extent = new CartographicExtent( ToDouble(record, 4, ByteOrder.LittleEndian), ToDouble(record, 12, ByteOrder.LittleEndian), ToDouble(record, 20, ByteOrder.LittleEndian), ToDouble(record, 28, ByteOrder.LittleEndian)); int numberOfParts = ToInteger(record, 36, ByteOrder.LittleEndian); numberOfPoints = ToInteger(record, 40, ByteOrder.LittleEndian); int[] parts = new int[numberOfParts]; Rectangular[] positions = new Rectangular[numberOfPoints]; // These two loops can be optimized if the machine is little endian. for (int i = 0; i < numberOfParts; ++i) { parts[i] = ToInteger(record, 44 + (4 * i), ByteOrder.LittleEndian); } int pointOffset = 44 + (4 * numberOfParts); int partTypeOffset = 44 + (4 * numberOfParts); if (recordShapeType == ShapeType.MultiPatch) { pointOffset = partTypeOffset + (4 * numberOfParts); } for (int i = 0; i < numberOfPoints; ++i) { positions[i] = new Rectangular( ToDouble(record, pointOffset + (16 * i), ByteOrder.LittleEndian), ToDouble(record, pointOffset + (16 * i) + 8, ByteOrder.LittleEndian)); } if (recordShapeType == ShapeType.Polyline) { _shapes.Add(new PolylineShape(recordNumber, metadata, extent, parts, positions)); } else if (recordShapeType == ShapeType.Polygon) { _shapes.Add(new PolygonShape(recordNumber, metadata, extent, parts, positions)); } else { mOffset = pointOffset + (16 * numberOfPoints); zOffset = pointOffset + (16 * numberOfPoints); if (recordShapeType == ShapeType.PolylineZ || recordShapeType == ShapeType.PolygonZ || recordShapeType == ShapeType.MultiPatch) { mOffset = zOffset + 16 + (8 * numberOfPoints); } double mMin = ToDouble(record, mOffset, ByteOrder.LittleEndian); double mMax = ToDouble(record, mOffset + 8, ByteOrder.LittleEndian); double[] measures = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { measures[i] = ToDouble(record, mOffset + 16 + (8 * i), ByteOrder.LittleEndian); } if (recordShapeType == ShapeType.PolylineM) { _shapes.Add(new PolylineMShape(recordNumber, metadata, extent, parts, positions, mMin, mMax, measures)); } else if (recordShapeType == ShapeType.PolygonM) { _shapes.Add(new PolygonMShape(recordNumber, metadata, extent, parts, positions, mMin, mMax, measures)); } else { double zMin = ToDouble(record, zOffset, ByteOrder.LittleEndian); double zMax = ToDouble(record, zOffset + 8, ByteOrder.LittleEndian); double[] zValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { zValues[i] = ToDouble(record, zOffset + 16 + (8 * i), ByteOrder.LittleEndian); } if (recordShapeType == ShapeType.PolylineZ) { _shapes.Add(new PolylineZShape(recordNumber, metadata, extent, parts, positions, zMin, zMax, zValues, mMin, mMax, measures)); } else if (recordShapeType == ShapeType.PolygonZ) { _shapes.Add(new PolygonZShape(recordNumber, metadata, extent, parts, positions, zMin, zMax, zValues, mMin, mMax, measures)); } else { MultiPatchPartType[] partTypes = new MultiPatchPartType[numberOfParts]; for (int i = 0; i < numberOfParts; i++) { partTypes[i] = (MultiPatchPartType)ToInteger(record, partTypeOffset + (4 * i), ByteOrder.LittleEndian); } _shapes.Add(new MultiPatchShape(recordNumber, metadata, extent, parts, partTypes, positions, zMin, zMax, zValues, mMin, mMax, measures)); } } } break; default: throw new NotImplementedException("The shapefile type is not supported. Only null, point, polyline, and polygon are supported."); } } } }
public void TestMultipatchConversionWithInnerAndOuterRings() { Rectangular[] positions = new Rectangular[] { new Rectangular(0.0, 5.0), new Rectangular(5.0, 10.0), new Rectangular(10.0, 5.0), new Rectangular(5.0, 0.0), new Rectangular(0.0, 5.0), new Rectangular(2.0, 5.0), new Rectangular(5.0, 2.0), new Rectangular(8.0, 5.0), new Rectangular(5.0, 8.0), new Rectangular(2.0, 5.0), }; CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0); int[] parts = new int[] { 0, 5 }; MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.OuterRing, MultiPatchPartType.InnerRing} ; double[] zValues = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures); MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue); patch.Write(); string result = m_stringWriter.ToString(); Assert.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(result, m_polygonPattern)); }