public void Faces_OfEachVertex_ShouldHaveTheSameOrderAsEdgesOfEachVertex (IPolyhedron polyhedron) { // Fixture setup // Exercise system var faces = VertexIndexedTableFactory.Faces(polyhedron); // Verify outcome for (int vertex = 0; vertex < polyhedron.Vertices.Count; vertex++) { var faceList = faces[vertex]; var edgeList = polyhedron.EdgesOf(polyhedron.Vertices[vertex]); var firstFace = polyhedron.Faces[faceList[0]]; var lastEdge = edgeList[edgeList.Count - 1]; var firstEdge = edgeList[0]; Assert.True(polyhedron.EdgesOf(firstFace).Contains(lastEdge)); Assert.True(polyhedron.EdgesOf(firstFace).Contains(firstEdge)); for (int i = 1; i < edgeList.Count; i++) { var thisFace = polyhedron.Faces[faceList[i]]; var previousEdge = edgeList[i - 1]; var thisEdge = edgeList[i]; Assert.True(polyhedron.EdgesOf(thisFace).Contains(previousEdge)); Assert.True(polyhedron.EdgesOf(thisFace).Contains(thisEdge)); } } // Teardown }
/// <summary> /// Calculates the size of the area that's both in the specified face and closer to the specified vertex than any other vertex. /// </summary> public static double AreaSharedByVertexAndFace(IPolyhedron surface, Vertex vertex, Face face) { var vertexPosition = vertex.Position; var faces = surface.FacesOf(vertex); var edges = surface.EdgesOf(vertex); var index = faces.IndexOf(face); if (!faces.Contains(face)) { return(0.0); } var midpointOfFace = face.Center(); var previousEdge = edges.AtCyclicIndex(index - 1); var midpointOfPreviousEdge = BisectionPoint(surface, previousEdge); var nextEdge = edges.AtCyclicIndex(index); var midpointOfNextEdge = BisectionPoint(surface, nextEdge); var crossProductOfFirstSegment = Vector.CrossProduct(midpointOfPreviousEdge - vertexPosition, midpointOfFace - vertexPosition); var areaOfFirstSegment = Vector.ScalarProduct(crossProductOfFirstSegment, midpointOfFace.Normalize()) / 2; var crossProductOfSecondSegment = Vector.CrossProduct(midpointOfFace - vertexPosition, midpointOfNextEdge - vertexPosition); var areaOfSecondSegment = Vector.ScalarProduct(crossProductOfSecondSegment, midpointOfFace.Normalize()) / 2; return(areaOfFirstSegment + areaOfSecondSegment); }
/// <summary> /// Returns the neighbours of a vertex in the same order that their connecting edges are listed by the /// polyhedron's vertexToEdge lookup. /// </summary> /// <param name="polyhedron"></param> /// <param name="vertex"></param> /// <returns></returns> public static IEnumerable <Vertex> NeighboursOf(this IPolyhedron polyhedron, Vertex vertex) { var vertexSingleton = new[] { vertex }; var edges = polyhedron.EdgesOf(vertex); var neighbours = edges.SelectMany(edge => edge.Vertices().Except(vertexSingleton)); return(neighbours.Where(neighbour => neighbour != vertex)); }
/// <summary> /// Returns the neighbours of a face in the same order that the edges they have in common appear. /// </summary> public static IEnumerable <Face> NeighboursOf(this IPolyhedron polyhedron, Face face) { var faceSingleton = new[] { face }; var edges = polyhedron.EdgesOf(face); var neighbours = edges.SelectMany(edge => polyhedron.FacesOf(edge).Except(faceSingleton)); return(neighbours); }
/// <summary> /// Constructs a table of the lengths of edges surrounding each face. /// Edges are listed in the same order as the opposing faces are given by surface.NeighboursOf. /// </summary> public static double[][] EdgeLengths(IPolyhedron surface) { var edgeLengths = new double[surface.Faces.Count][]; foreach (var face in surface.Faces) { var lengths = surface.EdgesOf(face).Select(edge => edge.Length()); edgeLengths[surface.IndexOf(face)] = lengths.ToArray(); } return(edgeLengths); }
/// <summary> /// Constructs a table of the spherical distances from each vertex to its neighbours. /// </summary> public static double[][] Distances(IPolyhedron surface) { var distanceTable = new double[surface.Vertices.Count][]; foreach (var vertex in surface.Vertices) { var edges = surface.EdgesOf(vertex); var distances = edges.Select(edge => edge.Length()).ToArray(); distanceTable[surface.IndexOf(vertex)] = distances; } return(distanceTable); }
private static int[] FacesAroundVertex(Vertex vertex, IPolyhedron surface) { var edges = surface.EdgesOf(vertex); var faces = new List <int>(); for (int i = 0; i < edges.Count; i++) { var previousEdge = edges.AtCyclicIndex(i - 1); var thisEdge = edges[i]; var faceInCommon = surface.FacesOf(previousEdge).Intersect(surface.FacesOf(thisEdge)).First(); var indexOfFace = surface.IndexOf(faceInCommon); faces.Add(indexOfFace); } return(faces.ToArray()); }
public void FacesOf_OnEachVertex_IsInCorrectOrderWithRespectToEdgesOf (IPolyhedron polyhedron) { // Fixture setup // Exercise system // Verify outcome foreach (var vertex in polyhedron.Vertices) { var edges = polyhedron.EdgesOf(vertex); var expected = edges.SelectMany((edge, i) => polyhedron.FacesOf(edge).Intersect(polyhedron.FacesOf(edges.AtCyclicIndex(i - 1)))).ToList(); var actual = polyhedron.FacesOf(vertex); TestUtilities.WriteExpectedAndActual(expected, actual); Assert.True(Enumerable.SequenceEqual(expected, actual)); } // Teardown }
public void EdgesOf_OverEachFace_IsInCorrectOrderWithRespectToTheVerticesOfTheFace (IPolyhedron polyhedron) { // Fixture setup // Exercise system // Verify outcome foreach (var face in polyhedron.Faces) { var expected = face.Vertices; var edges = polyhedron.EdgesOf(face); var actual = edges.SelectMany((edge, i) => edge.Vertices().Intersect(edges.AtCyclicIndex(i - 1).Vertices())).ToList(); TestUtilities.WriteExpectedAndActual(expected, actual); Assert.True(Enumerable.SequenceEqual(expected, actual)); } // Teardown }
/// <summary> /// Constructs a table of the distances from each vertex to the bisectors running across each neighbouring edge. /// </summary> public static double[][] HalfEdgeLengths(IPolyhedron surface) { var halfLengthsTable = new double[surface.Vertices.Count][]; foreach (var vertex in surface.Vertices) { var edges = surface.EdgesOf(vertex); var lengths = new List <double>(); foreach (var edge in edges) { var neighbour = edge.Vertices().First(v => v != vertex); var bisectionPoint = PolyhedronUtilities.BisectionPoint(surface, edge); var length = (neighbour.Position - bisectionPoint).Norm(); //TODO: This is planar distance, not geodesic. lengths.Add(length); } halfLengthsTable[surface.IndexOf(vertex)] = lengths.ToArray(); } return(halfLengthsTable); }
public void EdgesOf_OverEachFace_ReturnsEdgesInAnticlockwiseOrder (IPolyhedron polyhedron) { // Fixture setup // Exercise system var facesAndEdges = polyhedron.Faces.ToDictionary(face => face, face => polyhedron.EdgesOf(face)); // Verify outcome foreach (var faceAndEdges in facesAndEdges) { var face = faceAndEdges.Key; var center = face.SphericalCenter(); var viewDirection = -center; var edges = faceAndEdges.Value; var vectors = edges.Select(edge => edge.SphericalCenter()).ToList(); Assert.True(TestUtilities.AreInAntiClockwiseOrder(vectors, center, viewDirection)); } // Teardown }