diff --git a/src/BRepMesh/BRepMesh_Delaun.cxx b/src/BRepMesh/BRepMesh_Delaun.cxx index 16371015..d265f81b 100644 --- a/src/BRepMesh/BRepMesh_Delaun.cxx +++ b/src/BRepMesh/BRepMesh_Delaun.cxx @@ -14,6 +14,7 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. +#include "BRepMesh_HeapSort.hxx" #include #include @@ -268,8 +269,8 @@ void BRepMesh_Delaun::perform(IMeshData::VectorOfInteger& theVertexIndices, superMesh(aBox); ComparatorOfIndexedVertexOfDelaun aCmp(myMeshData); - std::make_heap(theVertexIndices.begin(), theVertexIndices.end(), aCmp); - std::sort_heap(theVertexIndices.begin(), theVertexIndices.end(), aCmp); + BRepMesh_HeapSort::MakeHeap(theVertexIndices.begin(), theVertexIndices.end(), aCmp); + BRepMesh_HeapSort::SortHeap(theVertexIndices.begin(), theVertexIndices.end(), aCmp); compute(theVertexIndices); } @@ -2221,8 +2222,8 @@ void BRepMesh_Delaun::AddVertices(IMeshData::VectorOfInteger& theVertices, const Message_ProgressRange& theRange) { ComparatorOfIndexedVertexOfDelaun aCmp(myMeshData); - std::make_heap(theVertices.begin(), theVertices.end(), aCmp); - std::sort_heap(theVertices.begin(), theVertices.end(), aCmp); + BRepMesh_HeapSort::MakeHeap(theVertices.begin(), theVertices.end(), aCmp); + BRepMesh_HeapSort::SortHeap(theVertices.begin(), theVertices.end(), aCmp); createTrianglesOnNewVertices(theVertices, theRange); } diff --git a/src/BRepMesh/BRepMesh_HeapSort.hxx b/src/BRepMesh/BRepMesh_HeapSort.hxx new file mode 100644 index 00000000..7c840d70 --- /dev/null +++ b/src/BRepMesh/BRepMesh_HeapSort.hxx @@ -0,0 +1,81 @@ +// Heap sort that orders equal elements exactly as GNU libstdc++'s std::make_heap / std::sort_heap do. +// +// BRepMesh_Delaun inserts vertices in the order a heap sort leaves them, and a regular grid (a torus, +// a cylinder) has many vertices its comparator calls equal. Which of those comes first decides the +// triangulation, and libc++ (Apple, LLVM) and libstdc++ (Linux) break the ties differently, so one model +// meshes differently on the two. This is the classic SGI STL algorithm libstdc++ implements, so every +// platform meshes as Linux does. +#ifndef BRepMesh_HeapSort_HeaderFile +#define BRepMesh_HeapSort_HeaderFile + +#include +#include + +namespace BRepMesh_HeapSort +{ +template +void PushHeap(It theFirst, Dist theHole, Dist theTop, T theValue, Cmp& theCmp) +{ + Dist aParent = (theHole - 1) / 2; + while (theHole > theTop && theCmp(*(theFirst + aParent), theValue)) + { + *(theFirst + theHole) = std::move(*(theFirst + aParent)); + theHole = aParent; + aParent = (theHole - 1) / 2; + } + *(theFirst + theHole) = std::move(theValue); +} + +template +void AdjustHeap(It theFirst, Dist theHole, Dist theLen, T theValue, Cmp& theCmp) +{ + const Dist aTop = theHole; + Dist aChild = theHole; + while (aChild < (theLen - 1) / 2) + { + aChild = 2 * (aChild + 1); + if (theCmp(*(theFirst + aChild), *(theFirst + (aChild - 1)))) + aChild--; + *(theFirst + theHole) = std::move(*(theFirst + aChild)); + theHole = aChild; + } + if ((theLen & 1) == 0 && aChild == (theLen - 2) / 2) + { + aChild = 2 * (aChild + 1); + *(theFirst + theHole) = std::move(*(theFirst + (aChild - 1))); + theHole = aChild - 1; + } + PushHeap(theFirst, theHole, aTop, std::move(theValue), theCmp); +} + +template +void MakeHeap(It theFirst, It theLast, Cmp theCmp) +{ + typedef typename std::iterator_traits::difference_type Dist; + const Dist aLen = theLast - theFirst; + if (aLen < 2) + return; + for (Dist aParent = (aLen - 2) / 2;; aParent--) + { + auto aValue = std::move(*(theFirst + aParent)); + AdjustHeap(theFirst, aParent, aLen, std::move(aValue), theCmp); + if (aParent == 0) + return; + } +} + +template +void SortHeap(It theFirst, It theLast, Cmp theCmp) +{ + typedef typename std::iterator_traits::difference_type Dist; + while (theLast - theFirst > 1) + { + --theLast; + auto aValue = std::move(*theLast); + *theLast = std::move(*theFirst); + AdjustHeap(theFirst, Dist(0), Dist(theLast - theFirst), std::move(aValue), theCmp); + } +} +} // namespace BRepMesh_HeapSort + +#endif