/// <summary>
        /// Инициализировать корпус, если Vertices.Length == Dimension.
        /// </summary>
        void InitSingle()
        {
            var vertices = new int[Dimension];

            for (int i = 0; i < Vertices.Length; i++)
            {
                vertices[i] = i;
            }

            var newFace = FacePool[ObjectManager.GetFace()];

            newFace.Vertices = vertices;
            Array.Sort(vertices);
            MathHelper.CalculateFacePlane(newFace, Center);

            // Убедиться, что нормальная точка внизу в случае, если это используется для триангуляции
            if (newFace.Normal[Dimension - 1] >= 0.0)
            {
                for (int i = 0; i < Dimension; i++)
                {
                    newFace.Normal[i] *= -1.0;
                }
                newFace.Offset          = -newFace.Offset;
                newFace.IsNormalFlipped = !newFace.IsNormalFlipped;
            }

            ConvexFaces.Add(newFace.Index);
        }
Example #2
0
        /// <summary>
        /// Init the hull if Vertices.Length == Dimension.
        /// </summary>
        void InitSingle()
        {
            var vertices = new int[Dimension];

            for (int i = 0; i < Vertices.Length; i++)
            {
                vertices[i] = i;
            }

            var newFace = FacePool[ObjectManager.GetFace()];

            newFace.Vertices = vertices;
            Array.Sort(vertices);
            MathHelper.CalculateFacePlane(newFace, Center);

            // Make sure the normal point downwards in case this is used for triangulation
            if (newFace.Normal[Dimension - 1] >= 0.0)
            {
                for (int i = 0; i < Dimension; i++)
                {
                    newFace.Normal[i] *= -1.0;
                }
                newFace.Offset          = -newFace.Offset;
                newFace.IsNormalFlipped = !newFace.IsNormalFlipped;
            }

            ConvexFaces.Add(newFace.Index);
        }
        /// <summary>
        /// Find the (dimension+1) initial points and create the simplexes.
        /// Creates the initial simplex of n+1 vertices by using points from the bounding box.
        /// Special care is taken to ensure that the vertices chosen do not result in a degenerate shape
        /// where vertices are collinear (co-planar, etc). This would technically be resolved when additional
        /// vertices are checked in the main loop, but: 1) a degenerate simplex would not eliminate any other
        /// vertices (thus no savings there), 2) the creation of the face normal is prone to error.
        /// </summary>
        private void CreateInitialSimplex()
        {
            var initialPoints = FindInitialPoints();

            #region Create the first faces from (dimension + 1) vertices.

            var faces = new int[NumOfDimensions + 1];

            for (var i = 0; i < NumOfDimensions + 1; i++)
            {
                var vertices = new int[NumOfDimensions];
                for (int j = 0, k = 0; j <= NumOfDimensions; j++)
                {
                    if (i != j)
                    {
                        vertices[k++] = initialPoints[j];
                    }
                }
                var newFace = FacePool[ObjectManager.GetFace()];
                newFace.Vertices = vertices;
                Array.Sort(vertices);
                mathHelper.CalculateFacePlane(newFace, Center);
                faces[i] = newFace.Index;
            }
            // update the adjacency (check all pairs of faces)
            for (var i = 0; i < NumOfDimensions; i++)
            {
                for (var j = i + 1; j < NumOfDimensions + 1; j++)
                {
                    UpdateAdjacency(FacePool[faces[i]], FacePool[faces[j]]);
                }
            }

            #endregion

            #region Init the vertex beyond buffers.

            foreach (var faceIndex in faces)
            {
                var face = FacePool[faceIndex];
                FindBeyondVertices(face);
                if (face.VerticesBeyond.Count == 0)
                {
                    ConvexFaces.Add(face.Index);                                 // The face is on the hull
                }
                else
                {
                    UnprocessedFaces.Add(face);
                }
            }

            #endregion

            // Set all vertices to false (unvisited).
            foreach (var vertex in initialPoints)
            {
                VertexVisited[vertex] = false;
            }
        }
        /// <summary>
        /// Commits a cone and adds a vertex to the convex hull.
        /// </summary>
        private void CommitCone()
        {
            // Fill the adjacency.
            for (var i = 0; i < ConeFaceBuffer.Count; i++)
            {
                var face = ConeFaceBuffer[i];

                var newFace = face.Face;
                var adjacentFace = face.Pivot;
                var oldFace = face.OldFace;
                var orderedPivotIndex = face.FaceIndex;

                newFace.AdjacentFaces[orderedPivotIndex] = adjacentFace.Index;
                adjacentFace.AdjacentFaces[face.PivotIndex] = newFace.Index;

                // let there be a connection.
                for (var j = 0; j < NumOfDimensions; j++)
                {
                    if (j == orderedPivotIndex) continue;
                    var connector = ObjectManager.GetConnector();
                    connector.Update(newFace, j, NumOfDimensions);
                    ConnectFace(connector);
                }

                // the id adjacent face on the hull? If so, we can use simple method to find beyond vertices.
                if (adjacentFace.VerticesBeyond.Count == 0)
                    FindBeyondVertices(newFace, oldFace.VerticesBeyond);
                // it is slightly more effective if the face with the lower number of beyond vertices comes first.
                else if (adjacentFace.VerticesBeyond.Count < oldFace.VerticesBeyond.Count)
                    FindBeyondVertices(newFace, adjacentFace.VerticesBeyond, oldFace.VerticesBeyond);
                else
                    FindBeyondVertices(newFace, oldFace.VerticesBeyond, adjacentFace.VerticesBeyond);

                // This face will definitely lie on the hull
                if (newFace.VerticesBeyond.Count == 0)
                {
                    ConvexFaces.Add(newFace.Index);
                    UnprocessedFaces.Remove(newFace);
                    ObjectManager.DepositVertexBuffer(newFace.VerticesBeyond);
                    newFace.VerticesBeyond = EmptyBuffer;
                }
                else // Add the face to the list
                {
                    UnprocessedFaces.Add(newFace);
                }

                // recycle the object.
                ObjectManager.DepositDeferredFace(face);
            }

            // Recycle the affected faces.
            for (var fIndex = 0; fIndex < AffectedFaceBuffer.Count; fIndex++)
            {
                var face = AffectedFaceBuffer[fIndex];
                UnprocessedFaces.Remove(FacePool[face]);
                ObjectManager.DepositFace(face);
            }
        }
Example #5
0
        /// <summary>
        /// Find the (dimension+1) initial points and create the simplexes.
        /// </summary>
        void InitConvexHull()
        {
            if (Vertices.Length < Dimension)
            {
                // In this case, there cannot be a single convex face, so we return an empty result.
                return;
            }
            else if (Vertices.Length == Dimension)
            {
                // The vertices are all on the hull and form a single simplex.
                InitSingle();
                return;
            }

            var extremes      = FindExtremes();
            var initialPoints = FindInitialPoints(extremes);

            // Add the initial points to the convex hull.
            foreach (var vertex in initialPoints)
            {
                CurrentVertex = vertex;
                // update center must be called before adding the vertex.
                UpdateCenter();
                AddConvexVertex(vertex);

                // Mark the vertex so that it's not included in any beyond set.
                VertexMarks[vertex] = true;
            }

            // Create the initial simplexes.
            var faces = CreateInitialHull();

            // Init the vertex beyond buffers.
            foreach (var faceIndex in faces)
            {
                var face = FacePool[faceIndex];
                FindBeyondVertices(face);
                if (face.VerticesBeyond.Count == 0)
                {
                    ConvexFaces.Add(face.Index);                                 // The face is on the hull
                }
                else
                {
                    UnprocessedFaces.Add(face);
                }
            }

            // Unmark the vertices
            foreach (var vertex in initialPoints)
            {
                VertexMarks[vertex] = false;
            }
        }
        /// <summary>
        /// Найти (размер + 1) начальных точек и создать симплексы
        /// </summary>
        void InitConvexHull()
        {
            if (Vertices.Length < Dimension)
            {
                // В этом случае не может быть одной выпуклой поверхности, так что мы возвращаем пустой результат
                return;
            }
            else if (Vertices.Length == Dimension)
            {
                // Все вершины на корпусе и образуют единый симплекс
                InitSingle();
                return;
            }

            var extremes      = FindExtremes();
            var initialPoints = FindInitialPoints(extremes);

            // Добавление начальных точек в выпуклую оболочку
            foreach (var vertex in initialPoints)
            {
                CurrentVertex = vertex;
                // Центр обновления должен быть вызван, прежде чем добавить вершину
                UpdateCenter();

                // Отметьте вершину так, чтобы она не была включена за пределы
                VertexMarks[vertex] = true;
            }

            // Создать начальный симплекс
            var faces = CreateInitialHull(initialPoints);

            // Инициализировать вершины за пределами буфера
            foreach (var faceIndex in faces)
            {
                var face = FacePool[faceIndex];
                FindBeyondVertices(face);
                if (face.VerticesBeyond.Count == 0)
                {
                    ConvexFaces.Add(face.Index);                                 // The face is on the hull
                }
                else
                {
                    UnprocessedFaces.Add(face);
                }
            }

            // Снять выделение с вершин
            foreach (var vertex in initialPoints)
            {
                VertexMarks[vertex] = false;
            }
        }
        /// <summary>
        /// Handles singular vertex.
        /// </summary>
        private void HandleSingular()
        {
            SingularVertices.Add(CurrentVertex);

            // This means that all the affected faces must be on the hull and that all their "vertices beyond" are singular.
            for (var fIndex = 0; fIndex < AffectedFaceBuffer.Count; fIndex++)
            {
                var face = FacePool[AffectedFaceBuffer[fIndex]];
                var vb   = face.VerticesBeyond;
                for (var i = 0; i < vb.Count; i++)
                {
                    SingularVertices.Add(vb[i]);
                }

                ConvexFaces.Add(face.Index);
                UnprocessedFaces.Remove(face);
                ObjectManager.DepositVertexBuffer(face.VerticesBeyond);
                face.VerticesBeyond = EmptyBuffer;
            }
        }
Example #8
0
        /// <summary>
        /// Рукоятки исключительных вершин
        /// </summary>
        void HandleSingular()
        {
            RollbackCenter();
            SingularVertices.Add(CurrentVertex);

            // Это означает, что все затронутые грани должны находиться на корпусе и что все "вершины за пределами" единичны
            for (int fIndex = 0; fIndex < AffectedFaceBuffer.Count; fIndex++)
            {
                var face = FacePool[AffectedFaceBuffer[fIndex]];
                var vb   = face.VerticesBeyond;
                for (int i = 0; i < vb.Count; i++)
                {
                    SingularVertices.Add(vb[i]);
                }

                ConvexFaces.Add(face.Index);
                UnprocessedFaces.Remove(face);
                ObjectManager.DepositVertexBuffer(face.VerticesBeyond);
                face.VerticesBeyond = EmptyBuffer;
            }
        }
Example #9
0
        /// <summary>
        /// Фиксирует конус и добавляет вершину к выпуклой оболочки
        /// </summary>
        void CommitCone()
        {
            // Заполнение смежностей
            for (int i = 0; i < ConeFaceBuffer.Count; i++)
            {
                var face = ConeFaceBuffer[i];

                var newFace           = face.Face;
                var adjacentFace      = face.Pivot;
                var oldFace           = face.OldFace;
                var orderedPivotIndex = face.FaceIndex;

                newFace.AdjacentFaces[orderedPivotIndex]    = adjacentFace.Index;
                adjacentFace.AdjacentFaces[face.PivotIndex] = newFace.Index;

                // Пусть здесь будет соединение
                for (int j = 0; j < Dimension; j++)
                {
                    if (j == orderedPivotIndex)
                    {
                        continue;
                    }
                    var connector = ObjectManager.GetConnector();
                    connector.Update(newFace, j, Dimension);
                    ConnectFace(connector);
                }

                // Идентификатор смежной грани на корпусе? Если да, то мы можем использовать простой метод, чтобы найти вершины за пределами
                if (adjacentFace.VerticesBeyond.Count == 0)
                {
                    FindBeyondVertices(newFace, oldFace.VerticesBeyond);
                }
                // Это более эффективно, если грань с меньшим числом вершин не приходит первой
                else if (adjacentFace.VerticesBeyond.Count < oldFace.VerticesBeyond.Count)
                {
                    FindBeyondVertices(newFace, adjacentFace.VerticesBeyond, oldFace.VerticesBeyond);
                }
                else
                {
                    FindBeyondVertices(newFace, oldFace.VerticesBeyond, adjacentFace.VerticesBeyond);
                }

                // Это лицо, грань, лежит на холме
                if (newFace.VerticesBeyond.Count == 0)
                {
                    ConvexFaces.Add(newFace.Index);
                    UnprocessedFaces.Remove(newFace);
                    ObjectManager.DepositVertexBuffer(newFace.VerticesBeyond);
                    newFace.VerticesBeyond = EmptyBuffer;
                }
                else // Добавить грань в список
                {
                    UnprocessedFaces.Add(newFace);
                }

                // Утилизировать объект
                ObjectManager.DepositDeferredFace(face);
            }

            // Утилизировать поврежденные грани
            for (int fIndex = 0; fIndex < AffectedFaceBuffer.Count; fIndex++)
            {
                var face = AffectedFaceBuffer[fIndex];
                UnprocessedFaces.Remove(FacePool[face]);
                ObjectManager.DepositFace(face);
            }
        }