public void GetElevationRange() { TrimbleTINModel TTM = new TrimbleTINModel(); TTM.LoadFromFile(Path.Combine("TestData", "Bug36372.ttm")); TTM.GetElevationRange(out var MinElev, out var MaxElev); MinElev.Should().BeApproximately(22.5, 0.001); MaxElev.Should().BeApproximately(37.33, 0.001); }
/// <summary> /// Builds a SuperElevation LOD to SuperElevationProfile specifications as one vertex buffer and one index buffer. /// The order in which the buffers are built reflects the nesting in the TrProfile. The nesting order is: /// (Polylines (Vertices)). All vertices and indices are built contiguously for an LOD. /// </summary> /// <param name="viewer">Viewer.</param> /// <param name="worldPosition">WorldPosition.</param> /// <param name="iLOD">Index of LOD mesh to be generated from profile.</param> /// <param name="iLODItem">Index of LOD mesh to be generated from profile.</param> public new ShapePrimitive BuildPrimitive(Viewer viewer, WorldPosition worldPosition, int iLOD, int iLODItem) { // Call for track section to initialize itself if (DTrackData.IsCurved == 0) { LinearGen(); } else { CircArcGen(); } // Count vertices and indices LOD lod = (LOD)TrProfile.LODs[iLOD]; LODItem lodItem = (LODItem)lod.LODItems[iLODItem]; NumVertices = (int)(lodItem.NumVertices * (NumSections + 1)); NumIndices = (short)(lodItem.NumSegments * NumSections * 6); // (Cells x 2 triangles/cell x 3 indices/triangle) // Allocate memory for vertices and indices VertexList = new VertexPositionNormalTexture[NumVertices]; // numVertices is now aggregate TriangleListIndices = new short[NumIndices]; // as is NumIndices // Build the mesh for lod VertexIndex = 0; IndexIndex = 0; whichCase = 0; //0: no elevation (MaxElev=0), 1: start (startE = 0, Max!=end), //2: end (end=0, max!=start), 3: middle (start>0, end>0), 4: start and finish in one if (StartElev.AlmostEqual(0f, 0.001f) && MaxElev.AlmostEqual(0f, 0.001f) && EndElv.AlmostEqual(0f, 0.001f)) { whichCase = 0; //no elev } else if (StartElev.AlmostEqual(0f, 0.001f) && EndElv.AlmostEqual(0f, 0.001f)) { whichCase = 4; //finish/start in one } else if (StartElev.AlmostEqual(0f, 0.001f) && !EndElv.AlmostEqual(0f, 0.001f)) { whichCase = 1; //start } else if (EndElv.AlmostEqual(0f, 0.001f) && !StartElev.AlmostEqual(0f, 0.001f)) { whichCase = 2; //finish } else { whichCase = 3; //in middle } Matrix PreRotation = Matrix.Identity; elevated = MaxElev; if (whichCase == 3 || whichCase == 2) { PreRotation = Matrix.CreateRotationZ(-elevated * Math.Sign(DTrackData.param1)); } //if section is in the middle of curve, will only rotate the first set of vertex, others will follow the same rotation prevRotation = 0f; Vector3 tmp; // Initial load of baseline cross section polylines for this LOD only: foreach (Polyline pl in lodItem.Polylines) { foreach (Vertex v in pl.Vertices) { tmp = new Vector3(v.Position.X, v.Position.Y, v.Position.Z); if (whichCase == 3 || whichCase == 2) { tmp = Vector3.Transform(tmp, PreRotation); prevRotation = MaxElev; } VertexList[VertexIndex].Position = tmp; VertexList[VertexIndex].Normal = v.Normal; VertexList[VertexIndex].TextureCoordinate = v.TexCoord; VertexIndex++; } } // Initial load of base cross section complete // Now generate and load subsequent cross sections OldRadius = -center; uint stride = VertexIndex; offSet = 0; for (uint i = 0; i < NumSections; i++) { currentRotation = determineRotation(DTrackData.param1); elevated = currentRotation - prevRotation; prevRotation = currentRotation; if (DTrackData.param1 > 0) { elevated *= -1; } foreach (Polyline pl in lodItem.Polylines) { uint plv = 0; // Polyline vertex index foreach (Vertex v in pl.Vertices) { if (DTrackData.IsCurved == 0) { LinearGen(stride, pl); // Generation call } else { CircArcGen(stride, pl); } if (plv > 0) { // Sense for triangles is clockwise // First triangle: TriangleListIndices[IndexIndex++] = (short)VertexIndex; TriangleListIndices[IndexIndex++] = (short)(VertexIndex - 1 - stride); TriangleListIndices[IndexIndex++] = (short)(VertexIndex - 1); // Second triangle: TriangleListIndices[IndexIndex++] = (short)VertexIndex; TriangleListIndices[IndexIndex++] = (short)(VertexIndex - stride); TriangleListIndices[IndexIndex++] = (short)(VertexIndex - 1 - stride); } VertexIndex++; plv++; } } OldRadius = radius; // Get ready for next segment offSet++; } // Create and populate a new ShapePrimitive var indexBuffer = new IndexBuffer(viewer.GraphicsDevice, typeof(short), NumIndices, BufferUsage.WriteOnly); indexBuffer.SetData(TriangleListIndices); return(new ShapePrimitive(lodItem.LODMaterial, new SharedShape.VertexBufferSet(VertexList, viewer.GraphicsDevice), indexBuffer, 0, NumVertices, NumIndices / 3, new[] { -1 }, 0)); }