public static Mesh Compute(RectangleD rectangle, int numberOfPartitionsX, int numberOfPartitionsY) { if (numberOfPartitionsX < 0) { throw new ArgumentOutOfRangeException("numberOfPartitionsX"); } if (numberOfPartitionsY < 0) { throw new ArgumentOutOfRangeException("numberOfPartitionsY"); } Mesh mesh = new Mesh(); mesh.PrimitiveType = PrimitiveType.Triangles; mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise; int numberOfPositions = (numberOfPartitionsX + 1) * (numberOfPartitionsY + 1); VertexAttributeFloatVector2 positionsAttribute = new VertexAttributeFloatVector2("position", numberOfPositions); IList <Vector2F> positions = positionsAttribute.Values; mesh.Attributes.Add(positionsAttribute); int numberOfIndices = (numberOfPartitionsX * numberOfPartitionsY) * 6; IndicesUnsignedInt indices = new IndicesUnsignedInt(numberOfIndices); mesh.Indices = indices; // // Positions // Vector2D lowerLeft = rectangle.LowerLeft; Vector2D toUpperRight = rectangle.UpperRight - lowerLeft; for (int y = 0; y <= numberOfPartitionsY; ++y) { double deltaY = y / (double)numberOfPartitionsY; double currentY = lowerLeft.Y + (deltaY * toUpperRight.Y); for (int x = 0; x <= numberOfPartitionsX; ++x) { double deltaX = x / (double)numberOfPartitionsX; double currentX = lowerLeft.X + (deltaX * toUpperRight.X); positions.Add(new Vector2D(currentX, currentY).ToVector2F()); } } // // Indices // int rowDelta = numberOfPartitionsX + 1; int i = 0; for (int y = 0; y < numberOfPartitionsY; ++y) { for (int x = 0; x < numberOfPartitionsX; ++x) { indices.AddTriangle(new TriangleIndicesUnsignedInt(i, i + 1, rowDelta + (i + 1))); indices.AddTriangle(new TriangleIndicesUnsignedInt(i, rowDelta + (i + 1), rowDelta + i)); i += 1; } i += 1; } return(mesh); }
public Shapefile(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."); } int fileCode = ToInteger(fileHeader, 0, ByteOrder.BigEndian); if (fileCode != _fileCode) { // // Swap byte order and try again. // _byteOrder = ByteOrder.BigEndian; 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."); } _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); // TODO: Publicly expose these //double zMin = NoDataToZero(ToDouble(fileHeader, 68, ByteOrder.LittleEndian)); //double zMax = NoDataToZero(ToDouble(fileHeader, 76, ByteOrder.LittleEndian)); //double mMin = NoDataToZero(ToDouble(fileHeader, 84, ByteOrder.LittleEndian)); //double mMax = NoDataToZero(ToDouble(fileHeader, 92, 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 RectangleD(new Vector2D(xMin, yMin), new Vector2D(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; 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); 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: _shapes.Add(new PointShape(recordNumber, new Vector2D( ToDouble(record, 4, ByteOrder.LittleEndian), ToDouble(record, 12, ByteOrder.LittleEndian)))); break; case ShapeType.Polyline: case ShapeType.Polygon: RectangleD extent = new RectangleD( new Vector2D( ToDouble(record, 4, ByteOrder.LittleEndian), ToDouble(record, 12, ByteOrder.LittleEndian)), new Vector2D( ToDouble(record, 20, ByteOrder.LittleEndian), ToDouble(record, 28, ByteOrder.LittleEndian))); int numberOfParts = ToInteger(record, 36, ByteOrder.LittleEndian); int numberOfPoints = ToInteger(record, 40, ByteOrder.LittleEndian); int[] parts = new int[numberOfParts]; Vector2D[] points = new Vector2D[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 pointsOffset = 44 + (4 * numberOfParts); for (int i = 0; i < numberOfPoints; ++i) { points[i] = new Vector2D( ToDouble(record, pointsOffset + (16 * i), ByteOrder.LittleEndian), ToDouble(record, pointsOffset + (16 * i) + 8, ByteOrder.LittleEndian)); } if (recordShapeType == ShapeType.Polyline) { _shapes.Add(new PolylineShape(recordNumber, extent, parts, points)); } else { _shapes.Add(new PolygonShape(recordNumber, extent, parts, points)); } break; default: throw new NotImplementedException("The shapefile type is not supported. Only null, point, polyline, and polygon are supported."); } } } }