/****************************************************************************** * * The MIT License (MIT) * * MIConvexHull, Copyright (c) 2015 David Sehnal, Matthew Campbell * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * *****************************************************************************/ using System; namespace NWH.DWP2.MiConvexHull { /// /// A helper class for object allocation/storage. /// This helps the GC a lot as it prevents the creation of about 75% of /// new face objects (in the case of ConvexFaceInternal). In the case of /// FaceConnectors and DefferedFaces, the difference is even higher (in most /// cases O(1) vs O(number of created faces)). /// internal class ObjectManager { /// /// The dimension /// private readonly int Dimension; /// /// The deferred face stack /// private readonly SimpleList DeferredFaceStack; /// /// The empty buffer stack /// private readonly SimpleList EmptyBufferStack; /// /// The free face indices /// private readonly IndexBuffer FreeFaceIndices; /// /// The hull /// private readonly ConvexHullAlgorithm Hull; /// /// The connector stack /// private FaceConnector ConnectorStack; /// /// The face pool /// private ConvexFaceInternal[] FacePool; /// /// The face pool size /// private int FacePoolSize; /// /// The face pool capacity /// private int FacePoolCapacity; /// /// Create the manager. /// /// The hull. public ObjectManager(ConvexHullAlgorithm hull) { Dimension = hull.NumOfDimensions; Hull = hull; FacePool = hull.FacePool; FacePoolSize = 0; FacePoolCapacity = hull.FacePool.Length; FreeFaceIndices = new IndexBuffer(); EmptyBufferStack = new SimpleList(); DeferredFaceStack = new SimpleList(); } /// /// Return the face to the pool for later use. /// /// Index of the face. public void DepositFace(int faceIndex) { ConvexFaceInternal face = FacePool[faceIndex]; int[] af = face.AdjacentFaces; for (int i = 0; i < af.Length; i++) { af[i] = -1; } FreeFaceIndices.Push(faceIndex); } /// /// Reallocate the face pool, including the AffectedFaceFlags /// private void ReallocateFacePool() { ConvexFaceInternal[] newPool = new ConvexFaceInternal[2 * FacePoolCapacity]; bool[] 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; } /// /// Create a new face and put it in the pool. /// /// System.Int32. private int CreateFace() { int index = FacePoolSize; ConvexFaceInternal face = new ConvexFaceInternal(Dimension, index, GetVertexBuffer()); FacePoolSize++; if (FacePoolSize > FacePoolCapacity) { ReallocateFacePool(); } FacePool[index] = face; return index; } /// /// Return index of an unused face or creates a new one. /// /// System.Int32. public int GetFace() { if (FreeFaceIndices.Count > 0) { return FreeFaceIndices.Pop(); } return CreateFace(); } /// /// Store a face connector in the "embedded" linked list. /// /// The connector. public void DepositConnector(FaceConnector connector) { if (ConnectorStack == null) { connector.Next = null; ConnectorStack = connector; } else { connector.Next = ConnectorStack; ConnectorStack = connector; } } /// /// Get an unused face connector. If none is available, create it. /// /// FaceConnector. public FaceConnector GetConnector() { if (ConnectorStack == null) { return new FaceConnector(Dimension); } FaceConnector ret = ConnectorStack; ConnectorStack = ConnectorStack.Next; ret.Next = null; return ret; } /// /// Deposit the index buffer. /// /// The buffer. public void DepositVertexBuffer(IndexBuffer buffer) { buffer.Clear(); EmptyBufferStack.Push(buffer); } /// /// Get a store index buffer or create a new instance. /// /// IndexBuffer. public IndexBuffer GetVertexBuffer() { return EmptyBufferStack.Count != 0 ? EmptyBufferStack.Pop() : new IndexBuffer(); } /// /// Deposit the deferred face. /// /// The face. public void DepositDeferredFace(DeferredFace face) { DeferredFaceStack.Push(face); } /// /// Get the deferred face. /// /// DeferredFace. public DeferredFace GetDeferredFace() { return DeferredFaceStack.Count != 0 ? DeferredFaceStack.Pop() : new DeferredFace(); } } }