/*========================================================================= Program: Visualization Toolkit Module: vtkStaticEdgeLocatorTemplate.h Copyright (c) Kitware, Inc. All rights reserved. See LICENSE file for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkStaticEdgeLocatorTemplate * @brief templated locator for managing edges and associated data on edges * * * vtkStaticEdgeLocatorTemplate provides methods for ordering and tracking * edges, as well as associating data with edges. (An edge is a tuple (v0,v1) * with v0 < v1.) Typically this class may be used for isocontouring or any * operation that operates on edges and needs to determine whether duplicates * exist. The class is templated on 1) the type used to represent the id * tuple; and 2) the data associated with the edge. * * This class is non-incremental (i.e., static). That is, an array of edges * is provided and the locator is built from this array. Incremental * additions of new edges is not allowed (analogoues to vtkStaticPointLocator * and vtkStaticCellLocator). * * Finally, there are two distinct usage patterns for this class. One is to * inject edges and then later search for them. This pattern begins with * BuildLocator() and then is followed by repeated calls to IsInsertedEdge(). * Internally this operates on an array of EdgeTupleType. The second pattern * operates on an array of MergeTupleType. It simply sorts the array using * MergeEdges(), thereby grouping identical edges. An offset array is created * that refers to the beginning of each group, hence indirectly indicating * the number of unique edges, and providing O(1) access to each edge. * * @warning * The id tuple type can be specified via templating to reduce memory and * speed processing. * * @warning * By default, a parametric coordinate T is associated with edges. By using * the appropriate template parameter it is possible to associate other data * with each edge. Note however that this data is not used when comparing and * sorting the edges. (This could be changed - define appropriate comparison * operators.) * * @warning * This class has been threaded with vtkSMPTools. Using TBB or other * non-sequential type (set in the CMake variable * VTK_SMP_IMPLEMENTATION_TYPE) may improve performance significantly. * * @sa * vtkEdgeTable vtkStaticPointLocator vtkStaticCellLocator */ #ifndef vtkStaticEdgeLocatorTemplate_h #define vtkStaticEdgeLocatorTemplate_h #include #include /** * Definition of an edge tuple. Note that the TId template type may be * specified to manage memory resources, and provide increased speeds (e.g., * sort) by using smaller types (32-int versus 64-bit vtkIdType). It is * required that V0 < V1; the tuple constructor enforces this. */ template struct EdgeTuple { TId V0; TId V1; TED T; // Default constructor - nothing needs to be done EdgeTuple() {} // Construct an edge and ensure that the edge tuple (vo,v1) is // specified such that (v0V0 > this->V1) { TId tmp = this->V0; this->V0 = this->V1; this->V1 = tmp; } } bool operator==(const EdgeTuple& et) const { return ((this->V0 == et.V0 && this->V1 == et.V1) ? true : false); } bool IsEdge(TId v0, TId v1) const { if (v0 < v1) // ordered properly { return ((this->V0 == v0 && this->V1 == v1) ? true : false); } else // swap comparison required { return ((this->V0 == v1 && this->V1 == v0) ? true : false); } } // Sort on v0 first, then v1. bool operator<(const EdgeTuple& tup) const { if (this->V0 < tup.V0) return true; if (tup.V0 < this->V0) return false; if (this->V1 < tup.V1) return true; return false; } }; /** * Definition of an edge tuple using for creating an edge merge table. Note * that the TId template type may be specified to manage memory resources, * and provide increased speeds (e.g., sort) by using smaller types (32-int * versus 64-bit vtkIdType). It is required that V0 < V1. */ template struct MergeTuple { TId V0; TId V1; TId EId; // originating edge id TED T; // Default constructor - nothing needs to be done MergeTuple() {} // Construct an edge and ensure that the edge tuple (vo,v1) is // specified such that (v0V0 > this->V1) { TId tmp = this->V0; this->V0 = this->V1; this->V1 = tmp; } } bool operator==(const MergeTuple& et) const { return ((this->V0 == et.V0 && this->V1 == et.V1) ? true : false); } bool operator!=(const MergeTuple& et) const { return ((this->V0 != et.V0 || this->V1 != et.V1) ? true : false); } // Sort on v0 first, then v1. bool operator<(const MergeTuple& tup) const { if (this->V0 < tup.V0) return true; if (tup.V0 < this->V0) return false; if (this->V1 < tup.V1) return true; return false; } }; /** * Templated on types of ids defining an edge, and any data associated with * the edge. */ template class vtkStaticEdgeLocatorTemplate { public: //@{ /** * Some convenient typedefs. */ typedef EdgeTuple EdgeTupleType; typedef MergeTuple MergeTupleType; //@) /** * Construct an empty edge locator. */ vtkStaticEdgeLocatorTemplate() : NumEdges(0) , NumEdgesPerBin(5) , EdgeArray(nullptr) , EdgeOffsets(nullptr) , MinV0(0) , MaxV0(0) , V0Range(0) , NDivs(0) , MergeArray(nullptr) { } /** * Delete internal offset array. The edgeArray is provided from outside the * class and so not deleted. */ ~vtkStaticEdgeLocatorTemplate() { delete[] this->EdgeOffsets; } /** * Return the number of edges in the edge array. */ IDType GetNumberOfEdges() { return this->NumEdges; } /** * This method sorts (in place) an array of MergeTupleType (of length * numEdges) into separate groups, and allocates and returns an offset * array providing access to each group. Each grouping is a list of * duplicate edges. The method indicates the number of unique edges * numUniqueEdges. Note that the offset array end value * offsets[numUniqueEdges] = numEdges, i.e., total allocation of the * offsets array is numUniqueEdges+1. Also note that the EId contained in * the sorted MergeTuples can be used to renumber edges from initial ids * (possibly one of several duplicates) to unique edge ids. */ const IDType* MergeEdges( vtkIdType numEdges, MergeTupleType* edgeArray, vtkIdType& numUniqueEdges); /** * This method constructs the edge locator to be used when searching for * edges. Basically it does a sort of the provided numEdges edges (which * likely contains duplicates), and builds an offset table to provide rapid * access to edge (v0,v1). The sort is performed via a parallel * vtkSMPTools::Sort(). The provided array is modified in place. The * method returns the number of unique edges. */ vtkIdType BuildLocator(vtkIdType numEdges, EdgeTupleType* edgeArray); /** * Return the id of the edge indicated. If the edge has not been inserted * return <0. Note that the vertices (v0,v1) do not have to be in any * particular (ascending/descending) order. BuildLocator() should be called * prior to using this method. */ IDType IsInsertedEdge(IDType v0, IDType v1) const { // Ensure that data is consistent with what is expected. IDType V0, V1; if (v0 < v1) { V0 = v0; V1 = v1; } else { V0 = v1; V1 = v0; } if (V0 < this->MinV0 || V0 > this->MaxV0) { return -1; } // Bin and search for matching edge IDType curBin = this->HashBin(V0); IDType curId = this->EdgeOffsets[curBin]; IDType curV0 = this->EdgeArray[curId].V0; IDType num = this->GetNumberOfEdgesInBin(curBin); for (IDType i = 0; i < num; ++i) { while (curV0 < V0) { curId++; curV0 = this->EdgeArray[curId].V0; } if (curV0 > V0) { return -1; } else // matched v0, now find v1 { IDType curV1 = this->EdgeArray[curId].V1; while (curV1 < V1) { curId++; curV1 = this->EdgeArray[curId].V1; } if (curV1 > V1) { return -1; } else { return curId; } } } // loop over maximum possible candidates // Nothing found return -1; } /** * Return the ith edge in the edge array. Either obtain a non-negative * value i from IsInsertedEdge(); or use 0<=iEdgeArray)[i]; } protected: vtkIdType NumEdges; // Support BuildLocator usage pattern vtkIdType NumEdgesPerBin; EdgeTupleType* EdgeArray; IDType* EdgeOffsets; IDType MinV0; IDType MaxV0; IDType V0Range; int NDivs; IDType HashBin(IDType v) const { return ((v - this->MinV0) / this->NumEdgesPerBin); } IDType GetNumberOfEdgesInBin(IDType bin) const { return (this->EdgeOffsets[bin + 1] - this->EdgeOffsets[bin]); } // Support MergeEdges usage pattern MergeTupleType* MergeArray; std::vector MergeOffsets; private: vtkStaticEdgeLocatorTemplate(const vtkStaticEdgeLocatorTemplate&) = delete; void operator=(const vtkStaticEdgeLocatorTemplate&) = delete; }; #include "vtkStaticEdgeLocatorTemplate.txx" #endif // VTK-HeaderTest-Exclude: vtkStaticEdgeLocatorTemplate.h