/* From https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/IO/BinaryReader.cs * * public virtual unsafe float ReadSingle() * { * FillBuffer(4); * uint tmpBuffer = (uint)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24); * return *((float*)&tmpBuffer); * } * * public virtual unsafe double ReadDouble() * { * FillBuffer(8); * uint lo = (uint)(_buffer[0] | _buffer[1] << 8 | * _buffer[2] << 16 | _buffer[3] << 24); * uint hi = (uint)(_buffer[4] | _buffer[5] << 8 | * _buffer[6] << 16 | _buffer[7] << 24); * * ulong tmpBuffer = ((ulong)hi) << 32 | lo; * return *((double*)&tmpBuffer); * } * * public virtual short ReadInt16() * { * FillBuffer(2); * return (short)(_buffer[0] | _buffer[1] << 8); * } * * [CLSCompliant(false)] * public virtual ushort ReadUInt16() * { * FillBuffer(2); * return (ushort)(_buffer[0] | _buffer[1] << 8); * } * * public virtual int ReadInt32() * { * if (_isMemoryStream) * { * if (_stream == null) * { * throw Error.GetFileNotOpen(); * } * * // read directly from MemoryStream buffer * MemoryStream mStream = _stream as MemoryStream; * Debug.Assert(mStream != null, "_stream as MemoryStream != null"); * * return mStream.InternalReadInt32(); * } * else * { * FillBuffer(4); * return (int)(_buffer[0] | _buffer[1] << 8 | _buffer[2] << 16 | _buffer[3] << 24); * } * } */ /* Retain as reference implementation using the standard binary reader IO for comparison with * the optimised direct memory access implementation below. * /// <summary> * /// Reads the set of triangles in the model utilising the given reader * /// </summary> * /// <param name="reader"></param> * /// <param name="header"></param> * public void Read(BinaryReader reader, TTMHeader header) * { * Items = new Triangle[header.NumberOfTriangles]; * bool readInt16s = header.VertexNumberSize == sizeof(short); * * void Read(ref Triangle tri) * { * if (readInt16s) * { * tri.Vertex0 = reader.ReadInt16() - 1; * tri.Vertex1 = reader.ReadInt16() - 1; * tri.Vertex2 = reader.ReadInt16() - 1; * } * else * { * tri.Vertex0 = reader.ReadInt32() - 1; * tri.Vertex1 = reader.ReadInt32() - 1; * tri.Vertex2 = reader.ReadInt32() - 1; * } * * // This loop does not need to be executed since the reader repositions the reading location after each serialise in * //for (int i = 0; i < 3; i++) * //{ * // int NeighbourIndex = Utilities.ReadInteger(reader, header.TriangleNumberSize); * // SetNeighbour(i, (NeighbourIndex < 1 || NeighbourIndex > triangles.Items.Length) ? null : triangles.Items[NeighbourIndex - 1]); * //} * } * * int loopLimit = header.NumberOfTriangles; * for (int i = 0; i < loopLimit; i++) * { * long RecPos = reader.BaseStream.Position; * Read(ref Items[i]); * reader.BaseStream.Position = RecPos + header.TriangleRecordSize; * } * } */ /// <summary> /// Reads the set of triangles in the model utilising the given reader /// </summary> /// <param name="bytes"></param> /// <param name="bufPos"></param> /// <param name="header"></param> public void Read(byte[] bytes, int bufPos, TTMHeader header) { Items = new Triangle[header.NumberOfTriangles]; bool readInt16s = header.VertexNumberSize == sizeof(short); int loopLimit = header.NumberOfTriangles; for (int i = 0; i < loopLimit; i++) { if (readInt16s) { Items[i].Vertex0 = (bytes[bufPos] | bytes[bufPos + 1] << 8) - 1; Items[i].Vertex1 = (bytes[bufPos + 2] | bytes[bufPos + 3] << 8) - 1; Items[i].Vertex2 = (bytes[bufPos + 4] | bytes[bufPos + 5] << 8) - 1; } else { Items[i].Vertex0 = (bytes[bufPos] | bytes[bufPos + 1] << 8 | bytes[bufPos + 2] << 16 | bytes[bufPos + 3] << 24) - 1; Items[i].Vertex1 = (bytes[bufPos + 4] | bytes[bufPos + 5] << 8 | bytes[bufPos + 6] << 16 | bytes[bufPos + 7] << 24) - 1; Items[i].Vertex2 = (bytes[bufPos + 8] | bytes[bufPos + 9] << 8 | bytes[bufPos + 10] << 16 | bytes[bufPos + 11] << 24) - 1; } // This loop does not need to be executed since the reader repositions the reading location after each serialise in //for (int i = 0; i < 3; i++) //{ // int NeighbourIndex = Utilities.ReadInteger(reader, header.TriangleNumberSize); // SetNeighbour(i, (NeighbourIndex < 1 || NeighbourIndex > triangles.Items.Length) ? null : triangles.Items[NeighbourIndex - 1]); //} bufPos += header.TriangleRecordSize; } }
/// <summary> /// Builds a triangle mesh from the vertices contained in the TIN model. All /// triangles are discarded. When using BuildTINMesh, it is sufficient to /// populate the vertex list (using AddVertex()) with all the vertices /// requiring tinning, then calling BuildTINMesh. All points to be tinned must be /// added prior to calling BuilTINMesh. To build TIN surfaces incrementally /// use InitialiseInitialTriangles() and IncorporateCoordIntoTriangle() to /// construct the TIN mesh. /// </summary> /// <returns></returns> public bool BuildTINMesh() { Triangle CurrentTri = null; double MinElevation = 0, MaxElevation = 0; // Clear all existing triangles TIN.Triangles.Clear(); TIN.Triangles.Capacity = TIN.Vertices.Count * 2; // Update the physical extents of the TIN model TTMHeader LocalHeader = TIN.Header; TIN.Vertices.GetLimits(ref LocalHeader.MinimumEasting, ref LocalHeader.MinimumNorthing, ref MinElevation, ref LocalHeader.MaximumEasting, ref LocalHeader.MaximumNorthing, ref MaxElevation); TIN.Header = LocalHeader; // Set up the initial state to insert the coordinates into MakeMinimumBoundingRectangle(out TriVertex TL, out TriVertex TR, out TriVertex BL, out TriVertex BR); CreateInitialTriangles(TL, TR, BL, BR); // Make sure all the vertices are numbered correctly, along with the 4 MBR vertices TIN.Vertices.NumberVertices(); // Subtract the origin from the vertices to preserve numeric precision for (int I = 0; I < TIN.Vertices.Count; I++) { TIN.Vertices[I].X -= TIN.Header.MinimumEasting; TIN.Vertices[I].Y -= TIN.Header.MinimumNorthing; } // Iterate through all the vertices adding them to the surface DateTime StartTime = DateTime.UtcNow; surfaceWalkOverflowCount = 0; // Don't read the 4 vertices we added for the bounding rectangle tris int MaxRealVertex = TIN.Vertices.Count - 1 - 4; for (int I = 0; I < MaxRealVertex; I++) { if (!IncorporateCoord(TIN.Vertices[I], ref CurrentTri)) { return(false); } } DateTime FinishTime = DateTime.UtcNow; Log.LogInformation($"Coordinate incorporation took {FinishTime - StartTime} to process {TIN.Vertices.Count} vertices into {TIN.Triangles.Count} triangles " + $"at a rate of {TIN.Vertices.Count / ((FinishTime - StartTime).TotalSeconds)} vertices/sec, encountering {surfaceWalkOverflowCount} surface walk overflows"); // Add the origin back to the vertex positions to re-translate than back to their correct positions for (int I = 0; I < TIN.Vertices.Count; I++) { TIN.Vertices[I].X += TIN.Header.MinimumEasting; TIN.Vertices[I].Y += TIN.Header.MinimumNorthing; } RemoveCornerTriangles(MaxRealVertex + 1); return(true); }