/// <summary>
 /// Constructs a FieldManipulator instance that allows the cursor tracked by cursorTracker to interact with
 /// fields defined on polyhedron.
 /// </summary>
 /// <param name="polyhedron"></param>
 /// <param name="cursorTracker"></param>
 /// <param name="options"></param>
 public FieldManipulator(IPolyhedron polyhedron, CursorTracker cursorTracker, IFieldManipulatorOptions options)
 {
     _polyhedron    = polyhedron;
     _cursorTracker = cursorTracker;
     _settings      = new FieldManipulatorSettings(options);
     _options       = options;
 }
Пример #2
0
        private static Mesh BuildMesh(IPolyhedron surface)
        {
            var vertices  = CreateVertexArray(surface);
            var triangles = CreateTriangleArray(surface);

            return(CreateMesh(vertices, triangles));
        }
Пример #3
0
        public static ScalarField <Face> RandomScalarField(IPolyhedron polyhedron, double average, double deviation)
        {
            var prng   = new Random();
            var values = Enumerable.Repeat(deviation, polyhedron.Faces.Count).Select(i => average + (prng.NextDouble() - 0.5) * deviation).ToArray();

            return(new ScalarField <Face>(polyhedron.IndexOf, values));
        }
        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
        }
Пример #5
0
        public static VectorField <Vertex> RandomVectorField(IPolyhedron polyhedron, Vector average, double maxDeviation)
        {
            var prng   = new Random();
            var values = polyhedron.Vertices.Select(vertex => RandomLocalVector(prng, vertex.Position, average, maxDeviation)).ToArray();

            return(new VectorField <Vertex>(polyhedron.IndexOf, values));
        }
Пример #6
0
        public static ScalarField <Face> XDependentScalarField(IPolyhedron polyhedron, double average, double deviation)
        {
            var normals = FaceIndexedTableFactory.Normals(polyhedron);
            var values  = polyhedron.Faces.Select(face => average + deviation * normals[polyhedron.IndexOf(face)][0]).ToArray();

            return(new ScalarField <Face>(polyhedron.IndexOf, values));
        }
        /// <summary>
        /// Construct a color mapper for the given polyhedron and maintain the running averages of the extrema for
        /// the specified length of time.
        /// </summary>
        /// <param name="polyhedron"></param>
        /// <param name="lengthOfHistory"></param>
        public FieldColorer(IPolyhedron polyhedron, int lengthOfHistory)
        {
            _polyhedron = polyhedron;

            _faces            = VertexIndexedTableFactory.Faces(polyhedron);
            _maxAndMinTracker = new MaxAndMinTracker(lengthOfHistory);
        }
        private static int IndexOfFaceInVertex(IPolyhedron surface, Face face, Vertex vertex)
        {
            var facesAroundVertex = surface.FacesOf(vertex);
            var indexOfFace       = facesAroundVertex.IndexOf(face);

            return(indexOfFace);
        }
        /// <summary>
        /// Constructs a table of the spherical areas associated with each vertex.
        ///
        /// Only valid for degree-3 vertices.
        /// </summary>
        public static double[] Areas(IPolyhedron surface)
        {
            var areasInEachFace = AreaInEachFace(surface);
            var areas           = surface.Vertices.Select((vertex, i) => areasInEachFace[i].Sum()).ToArray();

            return(areas);
        }
Пример #10
0
        /// <summary>
        /// Calculates the Coriolis acceleration field for the given surface rotating at the given frequency.
        /// </summary>
        /// <param name="surface"></param>
        /// <param name="rotationFrequency"></param>
        /// <returns></returns>
        public static ScalarField <Face> CoriolisField(IPolyhedron surface, double rotationFrequency)
        {
            var angularVelocity = 2 * Math.PI * rotationFrequency;
            var values          = surface.Faces.Select(face => 2 * angularVelocity * face.SphericalCenter().Normalize()[2]).ToArray();

            return(new ScalarField <Face>(surface.IndexOf, values));
        }
        /// <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>
        /// Constructs a table of the areas of the faces.
        /// </summary>
        public static double[] Areas(IPolyhedron surface)
        {
            var areasInEachVertex = AreaInEachVertex(surface);
            var areas             = surface.Faces.Select((face, i) => areasInEachVertex[i].Sum()).ToArray();

            return(areas);
        }
Пример #13
0
        //TODO: Fix the dependency on the specific ordering of vertex vectors then face vectors.
        // Constructs Vector3 for at each Vertex and at the center of each Face. Returns an array which contains
        // the Vertex vectors followed by the Face vectors.
        private static Vector3[] CreateVertexArray(IPolyhedron surface)
        {
            var vertexVectors = surface.Vertices.Select(vertex => GraphicsUtilities.Vector3(vertex.Position));
            var faceVectors   = surface.Faces.Select(face => GraphicsUtilities.Vector3(face.SphericalCenter()));

            return(vertexVectors.Concat(faceVectors).ToArray());
        }
        /// <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 an updater for the provided geometry.
        /// </summary>
        /// <param name="polyhedron"></param>
        /// <param name="options"></param>
        public ParticlePositionUpdater(IPolyhedron polyhedron, IParticleMapOptions options)
        {
            _scaleFactor = (float)(options.ParticleSpeedScaleFactor * options.Timestep);

            _tracker         = new ParticleNeighbourhoodTracker(polyhedron, options.ParticleCount);
            _vertexPositions = GetVertexPositions(polyhedron);

            _vertexVelocities   = new Vector3[polyhedron.Vertices.Count];
            _particleVelocities = new Vector3[options.ParticleCount];
        }
        // Creates a new icosahedron by subdividing the provided icosasphere.
        private static IPolyhedron Subdivide(IPolyhedron icosasphere)
        {
            // Map each edge of the old icosasphere to a new vertex
            var oldEdgesToNewVertices = CreateNewVerticesFrom(icosasphere.Edges);

            // Create the new faces (each represented by a list of vertices) from the old icosasphere and the new vertices
            var newFaces = CreateFacesFrom(icosasphere.Faces, icosasphere.EdgesOf, oldEdgesToNewVertices);

            return(new Polyhedron(newFaces));
        }
Пример #18
0
        /// <summary>
        /// Construct a particle map for the given simulation geometry.
        /// </summary>
        /// <param name="polyhedron"></param>
        /// <param name="options"></param>
        public ParticleMapView(IPolyhedron polyhedron, IParticleMapOptions options)
        {
            _options = options;
            _radius  = (float)_options.Radius;

            _positions = CreateParticles(options.ParticleCount, _radius);

            _renewalScheduler = new ParticleRenewalScheduler(options);
            _positionUpdater  = new ParticlePositionUpdater(polyhedron, options);
            _renderingManager = new ParticleRenderingManager(options);
        }
        /// <summary>
        /// Constructs a table of the normals to the sphere at the center of each face.
        /// </summary>
        public static Vector[] Normals(IPolyhedron surface)
        {
            var normals = new Vector[surface.Faces.Count];

            foreach (var face in surface.Faces)
            {
                normals[surface.IndexOf(face)] = face.SphericalCenter().Normalize();
            }

            return(normals);
        }
        /// <summary>
        /// Constructs a table of the faces around each vertex.
        ///
        /// The ith edge given by surface.EdgesOf is anticlockwise of the ith face.
        /// </summary>
        public static int[][] Faces(IPolyhedron surface)
        {
            var faceTable = new int[surface.Vertices.Count][];

            foreach (var vertex in surface.Vertices)
            {
                faceTable[surface.IndexOf(vertex)] = FacesAroundVertex(vertex, surface);
            }

            return(faceTable);
        }
        // Constructs the dual of the provided icosasphere, returning a list of lists in which each list represents the
        // vertices of a face.
        private static List <List <Vertex> > DualofIcosasphere(IPolyhedron icosasphere)
        {
            // Map each icosasphere face to a geodesic sphere vertex
            var newVertexDict = icosasphere.Faces.ToDictionary(face => face, face => VertexAtCenterOf(face));
            // Gather the new vertices into lists that represent the faces of the geodesic sphere.
            var vertexLists =
                icosasphere.Vertices.
                Select(oldVertex => CreateFaceAbout(oldVertex, newVertexDict, icosasphere.FacesOf)).ToList();

            return(vertexLists);
        }
Пример #22
0
        /// <summary>
        /// Construct a field updated for the given surface.
        /// </summary>
        /// <param name="surface"></param>
        /// <param name="options"></param>
        public PrognosticFieldsUpdater(IPolyhedron surface, IModelParameters options)
        {
            _options            = options;
            _coriolisField      = SimulationUtilities.CoriolisField(surface, _options.RotationFrequency);
            _faceNormalsField   = SimulationUtilities.FaceNormalsField(surface);
            _vertexNormalsField = SimulationUtilities.VertexNormalsField(surface);

            _operators = new VectorFieldOperators(surface);

            _gravity = options.Gravity;
        }
        // Project the vertices of the given polyhedron onto a sphere of the specified radius.
        private static IPolyhedron ProjectOntoSphere(IPolyhedron polyhedron, double radius)
        {
            var newVertex =
                polyhedron.Vertices.
                ToDictionary(oldVertex => oldVertex, oldVertex => new Vertex(radius * oldVertex.Position.Normalize()));

            var newFaces =
                from face in polyhedron.Faces
                select face.Vertices.Select(oldVertex => newVertex[oldVertex]).ToList();

            return(new Polyhedron(newFaces.ToList()));
        }
        /// <summary>
        /// Constructs a table of the neighbours of each face.
        /// Neighbours are listed in the same order as given by surface.NeighboursOf.
        /// </summary>
        public static int[][] Neighbours(IPolyhedron surface)
        {
            var neighbours = new int[surface.Faces.Count][];

            foreach (var face in surface.Faces)
            {
                var indicesOfNeighbours = surface.NeighboursOf(face).Select(neighbour => surface.IndexOf(neighbour));
                neighbours[surface.IndexOf(face)] = indicesOfNeighbours.ToArray();
            }

            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>
        /// Calculates the point at which the specified edge is closest to the line between its neighbouring faces' centers.
        /// </summary>
        public static Vector BisectionPoint(IPolyhedron polyhedron, Edge edge)
        {
            var aFace  = polyhedron.FacesOf(edge).First();
            var origin = edge.A.Position;

            var edgeVector   = edge.B.Position - origin;
            var vectorToFace = aFace.SphericalCenter() - origin;

            var vectorToBisector = Vector.ScalarProduct(vectorToFace, edgeVector.Normalize()) * edgeVector.Normalize();

            return(vectorToBisector + origin);
        }
        public static Vector[] Normals(IPolyhedron surface)
        {
            var normals = new Vector[surface.Vertices.Count];

            foreach (var vertex in surface.Vertices)
            {
                var normal = vertex.Position.Normalize();
                normals[surface.IndexOf(vertex)] = normal;
            }

            return(normals);
        }
        /// <summary>
        /// Constructs a table of the index of each face in surface.Faces(vertex) for each vertex around that face.
        /// </summary>
        public static int[][] FaceInFacesOfVertices(IPolyhedron surface)
        {
            var indices = new int[surface.Faces.Count][];

            foreach (var face in surface.Faces)
            {
                var indicesOfFace = face.Vertices.Select(vertex => IndexOfFaceInVertex(surface, face, vertex)).ToArray();
                indices[surface.IndexOf(face)] = indicesOfFace;
            }

            return(indices);
        }
        /// <summary>
        /// Constructs a table of the indices of the vertices around each face.
        /// </summary>
        public static int[][] Vertices(IPolyhedron surface)
        {
            var indices = new int[surface.Faces.Count][];

            foreach (var face in surface.Faces)
            {
                var vertexIndices = face.Vertices.Select(vertex => surface.IndexOf(vertex)).ToArray();
                indices[surface.IndexOf(face)] = vertexIndices;
            }

            return(indices);
        }
        /// <summary>
        /// Constructs a table of the directions towards the faces neighbours in the face's tangent space.
        /// </summary>
        public static Vector[][] Directions(IPolyhedron surface)
        {
            var directions = new Vector[surface.Faces.Count][];

            foreach (var face in surface.Faces)
            {
                var neighboursOfFace = surface.NeighboursOf(face);
                var localDirections  = neighboursOfFace.Select(neighbour => Direction(face, neighbour));
                directions[surface.IndexOf(face)] = localDirections.ToArray();
            }

            return(directions);
        }