/// <summary> /// Check if the vertex is "visible" from the face. /// The vertex is "over face" if the return value is > Constants.PlaneDistanceTolerance. /// </summary> /// <param name="v"></param> /// <param name="f"></param> /// <returns>The vertex is "over face" if the result is positive.</returns> public double GetVertexDistance(int v, ConvexFaceInternal f) { var normal = f.Normal; var x = v * _dimension; return(f.Offset + normal.Select((t, i) => t * _positionData[x + i]).Sum()); }
/// <summary> /// Reallocate the face pool, including the AffectedFaceFlags /// </summary> private void ReallocateFacePool() { var newPool = new ConvexFaceInternal[2 * _facePoolCapacity]; var newTags = new bool[2 * _facePoolCapacity]; Array.Copy(_facePool, newPool, _facePoolCapacity); Buffer.BlockCopy(_hull.AffectedFaceFlags, 0, newTags, 0, _facePoolCapacity * sizeof(bool)); _facePoolCapacity = 2 * _facePoolCapacity; _hull.FacePool = newPool; _facePool = newPool; _hull.AffectedFaceFlags = newTags; }
/// <summary> /// Create a new face and put it in the pool. /// </summary> /// <returns></returns> private int CreateFace() { var index = _facePoolSize; var face = new ConvexFaceInternal(_dimension, index, GetVertexBuffer()); _facePoolSize++; if (_facePoolSize > _facePoolCapacity) { ReallocateFacePool(); } _facePool[index] = face; return(index); }
/// <summary> /// Computes the volume of an n-dimensional simplex. /// Buffer needs to be array of shape Dimension x Dimension. /// </summary> /// <param name="cell"></param> /// <param name="vertices"></param> /// <param name="buffer">Helper for the calculation to avoid unnecessary allocations.</param> /// <returns></returns> public static double GetSimplexVolume(ConvexFaceInternal cell, IList <IVertex> vertices, SimplexVolumeBuffer buffer) { var xs = cell.Vertices; var pivot = vertices[xs[0]].Position; var data = buffer.Data; var dim = buffer.Dimension; var f = 1.0; for (var i = 1; i < xs.Length; i++) { f *= i + 1; var point = vertices[xs[i]].Position; for (var j = 0; j < point.Length; j++) { data[j * dim + i - 1] = point[j] - pivot[j]; } } return(Math.Abs(DeterminantDestructive(buffer)) / f); }
/// <summary> /// Calculates the normal and offset of the hyper-plane given by the face's vertices. /// </summary> /// <param name="face"></param> /// <param name="center"></param> /// <returns></returns> public bool CalculateFacePlane(ConvexFaceInternal face, double[] center) { var vertices = face.Vertices; var normal = face.Normal; FindNormalVector(vertices, normal); if (double.IsNaN(normal[0])) { return(false); } var offset = 0.0; var centerDistance = 0.0; var fi = vertices[0] * _dimension; for (var i = 0; i < _dimension; i++) { var n = normal[i]; offset += n * _positionData[fi + i]; centerDistance += n * center[i]; } face.Offset = -offset; centerDistance -= offset; if (centerDistance > 0) { for (var i = 0; i < _dimension; i++) { normal[i] = -normal[i]; } face.Offset = offset; face.IsNormalFlipped = true; } else { face.IsNormalFlipped = false; } return(true); }
/// <summary> /// Updates the connector. /// </summary> /// <param name="face"></param> /// <param name="edgeIndex"></param> /// <param name="dim"></param> public void Update(ConvexFaceInternal face, int edgeIndex, int dim) { Face = face; EdgeIndex = edgeIndex; uint hashCode = 23; unchecked { var vs = face.Vertices; int i, c = 0; for (i = 0; i < edgeIndex; i++) { Vertices[c++] = vs[i]; hashCode += 31 * hashCode + (uint)vs[i]; } for (i = edgeIndex + 1; i < vs.Length; i++) { Vertices[c++] = vs[i]; hashCode += 31 * hashCode + (uint)vs[i]; } } HashCode = hashCode; }