/*========================================================================= Program: Visualization Toolkit Module: vtkReebGraph.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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. =========================================================================*/ /*---------------------------------------------------------------------------- Copyright (c) Sandia Corporation See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. ----------------------------------------------------------------------------*/ #include "vtkReebGraph.h" #include "vtkCell.h" #include "vtkEdgeListIterator.h" #include "vtkDataArray.h" #include "vtkIdTypeArray.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkReebGraphSimplificationMetric.h" #include "vtkUnstructuredGrid.h" #include "vtkVariantArray.h" #include #include #include #include //---------------------------------------------------------------------------- // Contain all of the internal data structures, and macros, in the // implementation. namespace { //---------------------------------------------------------------------------- inline static bool vtkReebGraphVertexSoS(const std::pair &v0, const std::pair &v1) { return ((v0.second < v1.second) || ((v0.second == v1.second)&&(v0.first < v1.first))); } } // INTERNAL MACROS --------------------------------------------------------- #define vtkReebGraphSwapVars(type, var1, var2) \ {\ type tmp;\ tmp=(var1);\ (var1)=(var2);\ (var2)=tmp;\ } #define vtkReebGraphInitialStreamSize 1000 #define vtkReebGraphIsSmaller(myReebGraph, nodeId0, nodeId1, node0, node1) \ ((node0->Value < node1->Value) || (node0->Value == node1->Value && (nodeId0) < (nodeId1))) #define vtkReebGraphGetArcPersistence(rg,a) \ ((this->GetNode(a->NodeId1)->Value - this->GetNode(a->NodeId0)->Value) \ /(this->MaximumScalarValue - this->MinimumScalarValue)) #define vtkReebGraphIsHigherThan(rg,N0,N1,n0,n1) \ ((n0->Value >n1->Value) || (n0->Value==n1->Value && n0->VertexId>n1->VertexId)) // Note: usually this macro is called after the node has been finalized, // otherwise the behaviour is undefined. #define vtkReebGraphIsRegular(rg,n) \ ((!(n)->IsCritical) && \ ((n)->ArcDownId && !this->GetArc((n)->ArcDownId)->ArcDwId1 && \ (n)->ArcUpId && !this->GetArc((n)->ArcUpId)->ArcDwId0)) #define vtkReebGraphAddUpArc(rg,N,A) {\ vtkReebNode* n = this->GetNode(N);\ vtkReebArc* a = this->GetArc(A); \ a->ArcUpId0=0;a->ArcDwId0=n->ArcUpId;\ if (n->ArcUpId) this->GetArc(n->ArcUpId)->ArcUpId0=(A);\ n->ArcUpId=(A);\ } #define vtkReebGraphAddDownArc(rg,N,A) {\ vtkReebNode* n = this->GetNode(N);\ vtkReebArc* a = this->GetArc(A);\ a->ArcUpId1=0;\ a->ArcDwId1=n->ArcDownId;\ if (n->ArcDownId) this->GetArc(n->ArcDownId)->ArcUpId1=(A);\ n->ArcDownId=(A);\ } #define vtkReebGraphRemoveUpArc(rg,N,A) {\ vtkReebNode* n = this->GetNode(N);\ vtkReebArc* a = this->GetArc(A);\ if (a->ArcUpId0) this->GetArc(a->ArcUpId0)->ArcDwId0=a->ArcDwId0; else n->ArcUpId=a->ArcDwId0;\ if (a->ArcDwId0) this->GetArc(a->ArcDwId0)->ArcUpId0=a->ArcUpId0;} #define vtkReebGraphRemoveDownArc(rg,N,A) {\ vtkReebNode* n = this->GetNode(N);\ vtkReebArc* a = this->GetArc(A);\ if (a->ArcUpId1) this->GetArc(a->ArcUpId1)->ArcDwId1=a->ArcDwId1; else n->ArcDownId=a->ArcDwId1;\ if (a->ArcDwId1) this->GetArc(a->ArcDwId1)->ArcUpId1=a->ArcUpId1;\ } #ifndef vtkReebGraphMax #define vtkReebGraphMax(a,b) (((a)>=(b))?(a):(b)) #endif #define vtkReebGraphStackPush(N) \ {\ if (nstack==mstack)\ {\ mstack=vtkReebGraphMax(128,mstack*2);\ int *oldstack = stack;\ stack=(int*)realloc(stack,sizeof(int)*mstack);\ if (!stack)\ {\ free(oldstack);\ assert(0 && "Ran out of memory");\ }\ } \ stack[nstack++]=(N);\ } #define vtkReebGraphStackSize() (nstack) #define vtkReebGraphStackTop() (stack[nstack-1]) #define vtkReebGraphStackPop() (--nstack) //---------------------------------------------------------------------------- // PIMPLed classes... class vtkReebGraph::Implementation { public: Implementation() { this->historyOn = false; this->MainNodeTable.Buffer = (vtkReebNode*)malloc(sizeof(vtkReebNode)*2); this->MainArcTable.Buffer = (vtkReebArc*)malloc(sizeof(vtkReebArc)*2); this->MainLabelTable.Buffer = (vtkReebLabel*)malloc(sizeof(vtkReebLabel)*2); this->MainNodeTable.Size=2; this->MainNodeTable.Number=1; //the item "0" is blocked this->MainArcTable.Size=2; this->MainArcTable.Number=1; this->MainLabelTable.Size=2; this->MainLabelTable.Number=1; this->MainNodeTable.FreeZone=1; // Clear node this->GetNode(1)->ArcUpId = ((int)-2); // Initialize DownArc this->GetNode(1)->ArcDownId = 0; this->MainArcTable.FreeZone=1; // Clear Arc label 1 this->GetArc(1)->LabelId1 = ((int)-2); // Initialize Arc label 0 this->GetArc(1)->LabelId0 = 0; this->MainLabelTable.FreeZone=1; // Clear label this->GetLabel(1)->HNext = ((int)-2); // Initialize Arc id this->GetLabel(1)->ArcId = 0; this->MinimumScalarValue = 0; this->MaximumScalarValue = 0; this->ArcNumber = 0; this->NodeNumber = 0; this->LoopNumber = 0; this->RemovedLoopNumber = 0; this->ArcLoopTable = nullptr; this->currentNodeId = 0; this->currentArcId = 0; // streaming support this->VertexMapSize = 0; this->VertexMapAllocatedSize = 0; this->TriangleVertexMapSize = 0; this->TriangleVertexMapAllocatedSize = 0; } ~Implementation() { free(this->MainNodeTable.Buffer); this->MainNodeTable.Buffer = nullptr; free(this->MainArcTable.Buffer); this->MainArcTable.Buffer = nullptr; free(this->MainLabelTable.Buffer); this->MainLabelTable.Buffer = nullptr; this->MainNodeTable.Size = this->MainNodeTable.Number = 0; this->MainArcTable.Size = this->MainArcTable.Number = 0; this->MainLabelTable.Size = this->MainLabelTable.Number = 0; this->MainNodeTable.FreeZone = 0; this->MainArcTable.FreeZone = 0; this->MainLabelTable.FreeZone = 0; if(this->ArcLoopTable) free(this->ArcLoopTable); if(this->VertexMapAllocatedSize) free(this->VertexMap); if(this->TriangleVertexMapAllocatedSize) free(this->TriangleVertexMap); } typedef unsigned long long vtkReebLabelTag; typedef struct _vtkReebCancellation{ std::vector > removedArcs; std::vector > insertedArcs; }vtkReebCancellation; // Node structure typedef struct { vtkIdType VertexId; double Value; vtkIdType ArcDownId; vtkIdType ArcUpId; bool IsFinalized; bool IsCritical; } vtkReebNode; // Arc structure typedef struct { vtkIdType NodeId0, ArcUpId0, ArcDwId0; vtkIdType NodeId1, ArcUpId1, ArcDwId1; vtkIdType LabelId0, LabelId1; } vtkReebArc; // Label structure typedef struct { vtkIdType ArcId; vtkIdType HPrev, HNext; // "horizontal" (for a single arc) vtkReebLabelTag label; vtkIdType VPrev, VNext; // "vertical" (for a sequence of arcs) } vtkReebLabel; struct vtkReebPath { double SimplificationValue; int ArcNumber; vtkIdType* ArcTable; int NodeNumber; vtkIdType* NodeTable; inline bool operator<( struct vtkReebPath const &E ) const { return !( (SimplificationValue < E.SimplificationValue) || (SimplificationValue == E.SimplificationValue && ArcNumber < E.ArcNumber) || (SimplificationValue == E.SimplificationValue && ArcNumber == E.ArcNumber && NodeTable[NodeNumber - 1] < E.NodeTable[E.NodeNumber - 1])); /* return !(( (MaximumScalarValue - MinimumScalarValue) < (E.MaximumScalarValue - E.MinimumScalarValue)) || ((MaximumScalarValue - MinimumScalarValue) == (E.MaximumScalarValue-E.MinimumScalarValue) && ArcNumber < E.ArcNumber) || ((MaximumScalarValue - MinimumScalarValue) == (E.MaximumScalarValue - E.MinimumScalarValue) && ArcNumber == E.ArcNumber && NodeTable[NodeNumber - 1] VertexStream; std::vector cancellationHistory; // Streaming support int VertexMapSize, VertexMapAllocatedSize, TriangleVertexMapSize, TriangleVertexMapAllocatedSize; bool historyOn; vtkIdType *VertexMap; int *TriangleVertexMap; double MinimumScalarValue, MaximumScalarValue; // Arcs and nodes int ArcNumber, NodeNumber; // Loops int LoopNumber, RemovedLoopNumber; vtkIdType *ArcLoopTable; // CC int ConnectedComponentNumber; std::map ScalarField; vtkIdType currentNodeId, currentArcId; vtkDataSet *inputMesh; vtkDataArray *inputScalarField; vtkReebGraph *Parent; }; //---------------------------------------------------------------------------- vtkReebGraph::Implementation::vtkReebNode* vtkReebGraph::Implementation::GetNode(vtkIdType nodeId) { return (this->MainNodeTable.Buffer + nodeId); } //---------------------------------------------------------------------------- vtkReebGraph::Implementation::vtkReebArc* vtkReebGraph::Implementation::GetArc(vtkIdType arcId) { return (this->MainArcTable.Buffer + arcId); } //---------------------------------------------------------------------------- vtkReebGraph::Implementation::vtkReebLabel* vtkReebGraph::Implementation::GetLabel(vtkIdType labelId) { return (this->MainLabelTable.Buffer + labelId); } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::CollapseVertex(vtkIdType N, vtkReebNode* n) { int Lb, Lnext, La; vtkReebLabel* lb; int _A0 = n->ArcDownId; int _A1 = n->ArcUpId; vtkReebArc* _a0 = this->GetArc(_A0); vtkReebArc* _a1 = this->GetArc(_A1); _a0->NodeId1 = _a1->NodeId1; _a0->ArcUpId1 = _a1->ArcUpId1; if (_a1->ArcUpId1) this->GetArc(_a1->ArcUpId1)->ArcDwId1 = _A0; _a0->ArcDwId1 = _a1->ArcDwId1; if(_a1->ArcDwId1) this->GetArc(_a1->ArcDwId1)->ArcUpId1 = _A0; if (this->GetNode(_a1->NodeId1)->ArcDownId == _A1) this->GetNode(_a1->NodeId1)->ArcDownId = _A0; for( Lb = _a1->LabelId0; Lb; Lb=Lnext ) { lb = this->GetLabel(Lb); Lnext = lb->HNext; if (lb->VPrev) { La=lb->VPrev; this->GetLabel(La)->VNext = lb->VNext; } if (lb->VNext) this->GetLabel(lb->VNext)->VPrev=lb->VPrev; //delete the label... this->GetLabel(Lb)->HNext = ((int)-2); this->GetLabel(Lb)->ArcId = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone=(Lb); --(this->MainLabelTable.Number); } //delete the arc from the graph... this->GetArc(_A1)->LabelId1 = ((int)-2); this->GetArc(_A1)->LabelId0 = this->MainArcTable.FreeZone; this->MainArcTable.FreeZone=(_A1); --(this->MainArcTable.Number); //delete the node from the graph... this->GetNode(N)->ArcUpId = ((int)-2); this->GetNode(N)->ArcDownId = this->MainNodeTable.FreeZone; this->MainNodeTable.FreeZone=(N); --(this->MainNodeTable.Number); } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::DeepCopy(Implementation *srcG) { MinimumScalarValue = srcG->MinimumScalarValue; MaximumScalarValue = srcG->MaximumScalarValue; inputMesh = srcG->inputMesh; inputScalarField = srcG->inputScalarField; ArcNumber = srcG->ArcNumber; NodeNumber = srcG->NodeNumber; LoopNumber = srcG->LoopNumber; ScalarField = srcG->ScalarField; VertexStream = srcG->VertexStream; if (srcG->MainArcTable.Buffer) { MainArcTable.Size = srcG->MainArcTable.Size; MainArcTable.Number = srcG->MainArcTable.Number; this->MainArcTable.Buffer = (vtkReebArc*)malloc( sizeof(vtkReebArc)*srcG->MainArcTable.Size); memcpy(this->MainArcTable.Buffer,srcG->MainArcTable.Buffer, sizeof(vtkReebArc)*srcG->MainArcTable.Size); } if (srcG->MainNodeTable.Buffer) { MainNodeTable.Size = srcG->MainNodeTable.Size; MainNodeTable.Number = srcG->MainNodeTable.Number; this->MainNodeTable.Buffer = (vtkReebNode*)malloc( sizeof(vtkReebNode)*srcG->MainNodeTable.Size); memcpy(this->MainNodeTable.Buffer,srcG->MainNodeTable.Buffer, sizeof(vtkReebNode)*srcG->MainNodeTable.Size); } if (srcG->MainLabelTable.Buffer) { MainLabelTable.Size = srcG->MainLabelTable.Size; MainLabelTable.Number = srcG->MainLabelTable.Number; this->MainLabelTable.Buffer = (vtkReebLabel*)malloc( sizeof(vtkReebLabel)*srcG->MainLabelTable.Size); memcpy(this->MainLabelTable.Buffer,srcG->MainLabelTable.Buffer, sizeof(vtkReebLabel)*srcG->MainLabelTable.Size); } if (srcG->ArcLoopTable) { this->ArcLoopTable=(vtkIdType *)malloc(sizeof(vtkIdType)*srcG->LoopNumber); memcpy(this->ArcLoopTable, srcG->ArcLoopTable,sizeof(vtkIdType)*srcG->LoopNumber); } if(srcG->VertexMapSize){ this->VertexMapSize = srcG->VertexMapSize; this->VertexMapAllocatedSize = srcG->VertexMapAllocatedSize; this->VertexMap = (vtkIdType *) malloc( sizeof(vtkIdType)*this->VertexMapAllocatedSize); memcpy(this->VertexMap, srcG->VertexMap, sizeof(vtkIdType)*srcG->VertexMapAllocatedSize); } if(srcG->TriangleVertexMapSize){ this->TriangleVertexMapSize = srcG->TriangleVertexMapSize; this->TriangleVertexMapAllocatedSize = srcG->TriangleVertexMapAllocatedSize; this->TriangleVertexMap = (int *) malloc( sizeof(int)*this->TriangleVertexMapAllocatedSize); memcpy(this->TriangleVertexMap, srcG->TriangleVertexMap, sizeof(int)*srcG->TriangleVertexMapAllocatedSize); } } //---------------------------------------------------------------------------- vtkStandardNewMacro(vtkReebGraph); //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::SetLabel(vtkIdType arcId, vtkReebLabelTag Label) { inputMesh = nullptr; ResizeMainLabelTable(1); //create a new label in the graph vtkIdType L = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone = this->GetLabel(L)->ArcId; ++(this->MainLabelTable.Number); memset(this->GetLabel(L),0,sizeof(vtkReebLabel)); vtkReebLabel* l = this->GetLabel(L); l->HPrev=0; l->HNext=0; this->GetArc(arcId)->LabelId0=L; this->GetArc(arcId)->LabelId1=L; l->ArcId = arcId; l->label=Label; vtkIdType Lp = FindDwLabel(this->GetArc(arcId)->NodeId0,Label); vtkIdType Ln = FindUpLabel(this->GetArc(arcId)->NodeId1,Label); l->VPrev=Lp; if (Lp) this->GetLabel(Lp)->VNext=L; l->VNext=Ln; if (Ln) this->GetLabel(Ln)->VPrev=L; } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::FastArcSimplify(vtkIdType arcId, int vtkNotUsed(ArcNumber), vtkIdType* vtkNotUsed(arcTable)) { // Remove the arc which opens the loop vtkIdType nodeId0 = this->GetArc(arcId)->NodeId0; vtkIdType nodeId1 = this->GetArc(arcId)->NodeId1; vtkReebArc *A = this->GetArc(arcId); vtkReebArc *B = nullptr; int down, middle, up; if(historyOn) { if(A->ArcDwId0) { B = this->GetArc(A->ArcDwId0); down = this->GetNode(B->NodeId0)->VertexId; middle = this->GetNode(A->NodeId0)->VertexId; up = this->GetNode(B->NodeId1)->VertexId; vtkReebCancellation c; c.removedArcs.push_back(std::pair(middle, up)); c.insertedArcs.push_back(std::pair(down, up)); this->cancellationHistory.push_back(c); } if(A->ArcDwId1) { B = this->GetArc(A->ArcDwId1); down = this->GetNode(B->NodeId0)->VertexId; middle = this->GetNode(A->NodeId0)->VertexId; up = this->GetNode(A->NodeId1)->VertexId; vtkReebCancellation c; c.removedArcs.push_back(std::pair(middle, up)); c.insertedArcs.push_back(std::pair(down, up)); this->cancellationHistory.push_back(c); } if(A->ArcUpId0) { B = this->GetArc(A->ArcUpId0); down = this->GetNode(A->NodeId0)->VertexId; middle = this->GetNode(A->NodeId1)->VertexId; up = this->GetNode(B->NodeId1)->VertexId; vtkReebCancellation c; c.removedArcs.push_back(std::pair(down, middle)); c.insertedArcs.push_back(std::pair(down, up)); this->cancellationHistory.push_back(c); } if(A->ArcUpId1) { B = this->GetArc(A->ArcUpId1); down = this->GetNode(B->NodeId0)->VertexId; middle = this->GetNode(A->NodeId1)->VertexId; up = this->GetNode(B->NodeId1)->VertexId; vtkReebCancellation c; c.removedArcs.push_back(std::pair(down, middle)); c.insertedArcs.push_back(std::pair(down, up)); this->cancellationHistory.push_back(c); } } vtkReebGraphRemoveUpArc(this, nodeId0, arcId); vtkReebGraphRemoveDownArc(this, nodeId1, arcId); //delete the arc from the graph... this->GetArc(arcId)->LabelId1 = ((int)-2); this->GetArc(arcId)->LabelId0 = this->MainArcTable.FreeZone; this->MainArcTable.FreeZone=(arcId); --(this->MainArcTable.Number); } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindGreater(vtkIdType nodeId, vtkIdType startingNodeId, vtkReebLabelTag label) { if (!this->GetNode(nodeId)->IsFinalized) return 0; //base case if (vtkReebGraphIsHigherThan(this, nodeId, startingNodeId, this->GetNode(nodeId), this->GetNode(startingNodeId))) return nodeId; //iterative case for (vtkIdType A = this->GetNode(nodeId)->ArcUpId; A; A = this->GetArc(A)->ArcDwId0) { vtkReebArc* a = this->GetArc(A); vtkIdType M = this->GetArc(A)->NodeId1; vtkReebNode* m = this->GetNode(M); if (a->LabelId0 || !m->IsFinalized) //other labels or not final node { continue; } if ((M = FindGreater(M, startingNodeId, label))) { if (label) { SetLabel(A, label); } return M; } } return 0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindLess(vtkIdType nodeId, vtkIdType startingNodeId, vtkReebLabelTag label) { if (!this->GetNode(nodeId)->IsFinalized) return 0; //base case if(vtkReebGraphIsSmaller(this, nodeId, startingNodeId, this->GetNode(nodeId), this->GetNode(startingNodeId))) return nodeId; //iterative case for (vtkIdType A = this->GetNode(nodeId)->ArcDownId; A; A = this->GetArc(A)->ArcDwId1) { vtkReebArc* a = this->GetArc(A); vtkIdType M = this->GetArc(A)->NodeId0; vtkReebNode* m = this->GetNode(M); if (a->LabelId0 || !m->IsFinalized) //other labels or not final node continue; if ((M = FindLess(M, startingNodeId, label))) { if (label) { SetLabel(A, label); } return M; } } return 0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindJoinNode(vtkIdType arcId, vtkReebLabelTag label, bool onePathOnly) { vtkIdType N = this->GetArc(arcId)->NodeId1; vtkIdType Ret,C; if (this->GetArc(arcId)->LabelId0 || !this->GetNode(N)->IsFinalized) //other labels or not final node return 0; if (onePathOnly && (this->GetArc(arcId)->ArcDwId0 || this->GetArc(arcId)->ArcUpId0)) return 0; //base case if (this->GetArc(arcId)->ArcDwId1 || this->GetArc(arcId)->ArcUpId1) { if (label) SetLabel(arcId, label); return N; } for (C = this->GetNode(N)->ArcUpId; C; C = this->GetArc(C)->ArcDwId0) { Ret = FindJoinNode(C, label, onePathOnly); if (Ret) { if (label) SetLabel(arcId, label); return Ret; } } return 0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindSplitNode(vtkIdType arcId, vtkReebLabelTag label, bool onePathOnly) { vtkIdType N = this->GetArc(arcId)->NodeId0; vtkIdType Ret,C; if (this->GetArc(arcId)->LabelId0 || !this->GetNode(N)->IsFinalized) //other labels or not final node return 0; if (onePathOnly && (this->GetArc(arcId)->ArcDwId1 || this->GetArc(arcId)->ArcUpId1)) return 0; //base case if (this->GetArc(arcId)->ArcDwId0 || this->GetArc(arcId)->ArcUpId0) { if (label) SetLabel(arcId, label); return N; } //iterative case for (C = this->GetNode(N)->ArcDownId; C; C = this->GetArc(C)->ArcDwId1) { Ret = FindSplitNode(C, label, onePathOnly); if (Ret) { if (label) SetLabel(arcId, label); return Ret; } } return 0; } //---------------------------------------------------------------------------- vtkReebGraph::Implementation::vtkReebPath vtkReebGraph::Implementation::FindPath(vtkIdType arcId, double simplificationThreshold, vtkReebGraphSimplificationMetric *metric) { vtkReebPath entry; std::priority_queue pq; int size; vtkIdType N0 = this->GetArc(arcId)->NodeId0; vtkIdType N1 = this->GetArc(arcId)->NodeId1; char* Ntouch = nullptr; char* Atouch = nullptr; // double simplificationValue = 0; if((!inputMesh)||(!metric)) { double f0 = this->GetNode(N0)->Value; double f1 = this->GetNode(N1)->Value; entry.SimplificationValue = (f1 - f0) /(this->MaximumScalarValue - this->MinimumScalarValue); } else { entry.SimplificationValue = ComputeCustomMetric(metric, this->GetArc(arcId)); } //the arc itself has a good persistence if (simplificationThreshold && entry.SimplificationValue>= simplificationThreshold) { NOT_FOUND: if (Ntouch) free(Ntouch); if (Atouch) free(Atouch); vtkReebPath fake;memset(&fake,0,sizeof(vtkReebPath)); fake.SimplificationValue = 1; return fake; } Atouch=(char*)malloc(sizeof(char)*this->MainArcTable.Size); Ntouch=(char*)malloc(sizeof(char)*this->MainNodeTable.Size); memset(Atouch,0,sizeof(char)*this->MainArcTable.Size); memset(Ntouch,0,sizeof(char)*this->MainNodeTable.Size); Ntouch[N0]=1; //I don't want to use the arc given by the user Atouch[arcId]=1; entry.NodeNumber=1; entry.NodeTable = new vtkIdType[1]; entry.NodeTable[0]=N0; entry.ArcNumber=0; entry.ArcTable =nullptr; pq.push(entry); while ((size=static_cast(pq.size()))) { entry=pq.top(); pq.pop(); int N=entry.NodeTable[entry.NodeNumber-1]; for (int dir=0;dir<=1;dir++) { for (int A = (!dir) ? this->GetNode(N)->ArcDownId : this->GetNode(N)->ArcUpId; A; A=(!dir) ? this->GetArc(A)->ArcDwId1 : this->GetArc(A)->ArcDwId0) { int M = (!dir) ? (this->GetArc(A)->NodeId0) : (this->GetArc(A)->NodeId1); if (Atouch[A]) continue; Atouch[A]=1; //already used (==there is a better path to reach M) if (Ntouch[M]) continue; Ntouch[M]=1; //found!!! if (M==N1) { //clear all the items in the priority queue while (!pq.empty()) { vtkReebPath aux=pq.top();pq.pop(); delete aux.ArcTable; delete aux.NodeTable; } free(Ntouch); free(Atouch); vtkIdType* tmp=new vtkIdType[entry.NodeNumber+1]; memcpy(tmp,entry.NodeTable,sizeof(vtkIdType)*entry.NodeNumber); tmp[entry.NodeNumber]=N1; delete [] entry.NodeTable; entry.NodeTable = tmp; entry.NodeNumber++; return entry; } if((!inputMesh)||(!metric)) { entry.SimplificationValue += vtkReebGraphGetArcPersistence(this, this->GetArc(A)); } else { entry.SimplificationValue += ComputeCustomMetric(metric, this->GetArc(A)); } // The loop persistence is greater than functionScale if(simplificationThreshold && entry.SimplificationValue >= simplificationThreshold) continue; vtkReebPath newentry; newentry.SimplificationValue = entry.SimplificationValue; newentry.ArcNumber = entry.ArcNumber+1; newentry.ArcTable = new vtkIdType [newentry.ArcNumber]; newentry.NodeNumber = entry.NodeNumber+1; newentry.NodeTable = new vtkIdType [newentry.NodeNumber]; if (entry.ArcNumber) memcpy(newentry.ArcTable,entry.ArcTable, sizeof(vtkIdType)*entry.ArcNumber); if (entry.NodeNumber) memcpy(newentry.NodeTable,entry.NodeTable, sizeof(vtkIdType)*entry.NodeNumber); newentry.ArcTable[entry.ArcNumber]=A; newentry.NodeTable[entry.NodeNumber]=M; pq.push(newentry); } } //finished with this entry delete entry.ArcTable; delete [] entry.NodeTable; } goto NOT_FOUND; } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::SimplifyLoops(double simplificationThreshold, vtkReebGraphSimplificationMetric *simplificationMetric) { if (!simplificationThreshold) return 0; // refresh information about ArcLoopTable this->FindLoops(); int NumSimplified=0; for (int n = 0; n < this->LoopNumber; n++) { int A = this->ArcLoopTable[n]; if (this->GetArc(A)->LabelId1 == ((int)-2)) continue; double simplificationValue = 0; if((!inputMesh)||(!simplificationMetric)) { vtkIdType N0 = this->GetArc(A)->NodeId0; vtkIdType N1 = this->GetArc(A)->NodeId1; double f0 = this->GetNode(N0)->Value; double f1 = this->GetNode(N1)->Value; simplificationValue = (f1 - f0) /(this->MaximumScalarValue - this->MinimumScalarValue); } else { simplificationValue = ComputeCustomMetric(simplificationMetric, this->GetArc(A)); } if(simplificationValue >= simplificationThreshold) continue; vtkReebPath entry = this->FindPath(this->ArcLoopTable[n], simplificationThreshold, simplificationMetric); //too high for persistence if(entry.SimplificationValue >= simplificationThreshold) continue; //distribute its bucket to the loop and delete the arc this->FastArcSimplify(ArcLoopTable[n],entry.ArcNumber,entry.ArcTable); delete entry.ArcTable; delete entry.NodeTable; ++NumSimplified; CommitSimplification(); } //check for regular points for (int N=1;NMainNodeTable.Size;N++) { if(this->GetNode(N)->ArcUpId == ((int)-2)) continue; if (this->GetNode(N)->ArcDownId==0 && this->GetNode(N)->ArcUpId==0) { //delete the node from the graph... this->GetNode(N)->ArcUpId = ((int)-2); this->GetNode(N)->ArcDownId = this->MainNodeTable.FreeZone; this->MainNodeTable.FreeZone=(N); --(this->MainNodeTable.Number); } else if (vtkReebGraphIsRegular(this,this->GetNode(N))) { if(historyOn) { vtkReebNode *n = this->GetNode(N); int A0 = n->ArcDownId; int A1 = n->ArcUpId; vtkReebArc *a0 = this->GetArc(A0); vtkReebArc *a1 = this->GetArc(A1); vtkReebNode *downN = this->GetNode(a0->NodeId0); vtkReebNode *upN = this->GetNode(a1->NodeId1); int down, middle, up; down = downN->VertexId; middle = n->VertexId; up = upN->VertexId; vtkReebCancellation c; c.removedArcs.push_back(std::pair(down, middle)); c.removedArcs.push_back(std::pair(middle, up)); c.insertedArcs.push_back(std::pair(down, up)); this->cancellationHistory.push_back(c); } EndVertex(N); } } this->RemovedLoopNumber = NumSimplified; return NumSimplified; } //---------------------------------------------------------------------------- double vtkReebGraph::Implementation::ComputeCustomMetric( vtkReebGraphSimplificationMetric *simplificationMetric, vtkReebArc *a) { int edgeId = -1, start = -1, end = -1; vtkDataArray *vertexInfo = vtkArrayDownCast( this->Parent->GetVertexData()->GetAbstractArray("Vertex Ids")); if(!vertexInfo) return vtkReebGraphGetArcPersistence(this, a); vtkVariantArray *edgeInfo = vtkArrayDownCast( this->Parent->GetEdgeData()->GetAbstractArray("Vertex Ids")); if(!edgeInfo) return vtkReebGraphGetArcPersistence(this, a); vtkEdgeListIterator *eIt = vtkEdgeListIterator::New(); this->Parent->GetEdges(eIt); do { vtkEdgeType e = eIt->Next(); if(((*(vertexInfo->GetTuple(e.Source))) == GetNodeVertexId(a->NodeId0)) &&((*(vertexInfo->GetTuple(e.Target))) == GetNodeVertexId(a->NodeId1))) { edgeId = e.Id; start = static_cast(*(vertexInfo->GetTuple(e.Source))); end = static_cast(*(vertexInfo->GetTuple(e.Target))); break; } }while(eIt->HasNext()); eIt->Delete(); vtkAbstractArray *vertexList = edgeInfo->GetPointer(edgeId)->ToArray(); return simplificationMetric->ComputeMetric(inputMesh, inputScalarField, start, vertexList, end); } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::SimplifyBranches(double simplificationThreshold, vtkReebGraphSimplificationMetric *simplificationMetric) { static const vtkReebLabelTag RouteOld=100; static const vtkReebLabelTag RouteNew=200; int nstack,mstack=0; int* stack=nullptr; if (!simplificationThreshold) return 0; int nsimp=0; int cont=0; const int step=10000; bool redo; vtkDataSet *input = inputMesh; REDO: nstack=0; redo=false; for (int N = 1; N < this->MainNodeTable.Size; ++N) { if(this->GetNode(N)->ArcUpId == ((int)-2)) continue; vtkReebNode* n = this->GetNode(N); //simplify atomic nodes if (!n->ArcDownId && !n->ArcUpId) { //delete the node from the graph... this->GetNode(N)->ArcUpId = ((int)-2); this->GetNode(N)->ArcDownId = this->MainNodeTable.FreeZone; this->MainNodeTable.FreeZone=(N); --(this->MainNodeTable.Number); } else if (!n->ArcDownId) { //insert into stack branches to simplify for (int _A_ = n->ArcUpId; _A_; _A_ = this->GetArc(_A_)->ArcDwId0) { vtkReebArc* _a_ = this->GetArc(_A_); if((!inputMesh)||(!simplificationMetric)) { if (vtkReebGraphGetArcPersistence(this,_a_)< simplificationThreshold) { vtkReebGraphStackPush(_A_); } } else { if(this->ComputeCustomMetric(simplificationMetric, _a_) < simplificationThreshold) { vtkReebGraphStackPush(_A_); } } } } else if (!n->ArcUpId) { //insert into stack branches to simplify for (int _A_=n->ArcDownId;_A_;_A_=this->GetArc(_A_)->ArcDwId1) { vtkReebArc* _a_ = this->GetArc(_A_); if (vtkReebGraphGetArcPersistence(this,_a_)< simplificationThreshold) { vtkReebGraphStackPush(_A_); } } } } while (vtkReebGraphStackSize()) { int A=vtkReebGraphStackTop();vtkReebGraphStackPop(); if (!--cont) { cont=step; } if (this->GetArc(A)->LabelId1 == ((int)-2)) continue; cont++; vtkReebArc* arc = this->GetArc(A); int N = arc->NodeId0; int M = arc->NodeId1; if (this->GetNode(N)->ArcDownId && this->GetNode(M)->ArcUpId) continue; double persistence = vtkReebGraphGetArcPersistence(this, arc); //is the actual persistence (in percentage) greater than the applied filter? if (persistence>=simplificationThreshold) continue; int _A, Mdown = 0, Nup = 0, Ndown = 0, Mup = 0; //get the 'down' degree for M for(_A = this->GetNode(M)->ArcDownId;_A;_A = this->GetArc(_A)->ArcDwId1) ++Mdown; //Get the 'up' degree for N for(_A = this->GetNode(N)->ArcUpId;_A;_A = this->GetArc(_A)->ArcDwId0) ++Nup; //get the 'down' degree for N for(_A = this->GetNode(N)->ArcDownId;_A;_A = this->GetArc(_A)->ArcDwId1) ++Ndown; //get the 'up' degree for M for(_A = this->GetNode(M)->ArcUpId;_A;_A = this->GetArc(_A)->ArcDwId0) ++Mup; //isolated arc if (!Ndown && Nup==1 && Mdown==1 && !Mup) { vtkReebGraphRemoveUpArc (this,N,A); vtkReebGraphRemoveDownArc(this,M,A); //delete the arc from the graph... this->GetArc(A)->LabelId1 = ((int)-2); this->GetArc(A)->LabelId0 = this->MainArcTable.FreeZone; this->MainArcTable.FreeZone=(A); --(this->MainArcTable.Number); if (!(this->GetNode(N)->ArcUpId == ((int)-2)) && vtkReebGraphIsRegular(this, this->GetNode(N))) { EndVertex(N); } if (!(this->GetNode(M)->ArcUpId == ((int)-2)) && vtkReebGraphIsRegular(this, this->GetNode(M))) { EndVertex(M); } nsimp++;redo=true; continue; } int Down=0; int Up=0; bool simplified=false; // M is a maximum if (!Mup) { if ((Down = FindSplitNode(A, RouteOld))) { if ((Up = FindGreater(Down, M, RouteNew))) { SetLabel(AddArc(M,Up),RouteOld); Collapse(Down,Up,RouteOld,RouteNew); simplified=true; } else { this->SimplifyLabels(Down); } } } //N is a minimum if (!simplified && !Ndown) { if ((Up = FindJoinNode(A, RouteOld))) { if ((Down = FindLess(Up, N, RouteNew))) { SetLabel(AddArc(Down,N),RouteOld); Collapse(Down,Up,RouteOld,RouteNew); simplified=true; } else { this->SimplifyLabels(Up); } } } if (simplified) { if (!(this->GetNode(Down)->ArcUpId == ((int)-2))) { this->SimplifyLabels(Down); if (!this->GetNode(Down)->ArcDownId) //minimum { for (vtkIdType _A_ = this->GetNode(Down)->ArcUpId; _A_; _A_ = this->GetArc(_A_)->ArcDwId0) { vtkReebArc* _a_ = this->GetArc(_A_); if((!inputMesh)||(!simplificationMetric)) { if (vtkReebGraphGetArcPersistence(this,_a_) < simplificationThreshold) { vtkReebGraphStackPush(_A_); } } else { if(this->ComputeCustomMetric(simplificationMetric, _a_) < simplificationThreshold) { vtkReebGraphStackPush(_A_); } } } } } if (!(this->GetNode(Up)->ArcUpId == ((int)-2))) { this->SimplifyLabels(Up); if (!this->GetNode(Up)->ArcUpId) { for (int _A_ = this->GetNode(Up)->ArcDownId; _A_; _A_ = this->GetArc(_A_)->ArcDwId1) { vtkReebArc* _a_ = this->GetArc(_A_); if((!inputMesh)||(!simplificationMetric)) { if (vtkReebGraphGetArcPersistence(this,_a_) < simplificationThreshold) { vtkReebGraphStackPush(_A_); } } else { if(this->ComputeCustomMetric(simplificationMetric, _a_) < simplificationThreshold) { vtkReebGraphStackPush(_A_); } } } } } nsimp++; redo=true; } CommitSimplification(); } //while if (redo) goto REDO; free(stack); inputMesh = input; return nsimp; } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::ResizeMainNodeTable(int newSize) { int oldsize,i; if ((this->MainNodeTable.Size-this->MainNodeTable.Number)< newSize) { oldsize=this->MainNodeTable.Size; if (!this->MainNodeTable.Size) this->MainNodeTable.Size = newSize; while ((this->MainNodeTable.Size-this->MainNodeTable.Number)< newSize) this->MainNodeTable.Size<<=1; this->MainNodeTable.Buffer = (vtkReebNode*)realloc( this->MainNodeTable.Buffer,sizeof(vtkReebNode)*this->MainNodeTable.Size); for (i=oldsize;iMainNodeTable.Size-1;i++) { this->GetNode(i)->ArcDownId=i+1; this->GetNode(i)->ArcUpId = ((int)-2); } this->GetNode(i)->ArcDownId = this->MainNodeTable.FreeZone; this->GetNode(i)->ArcUpId = ((int)-2); this->MainNodeTable.FreeZone=oldsize; } } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::CommitSimplification() { // now re-construct the graph with projected deg-2 nodes. std::vector, std::vector > > before, after; vtkEdgeListIterator *eIt = vtkEdgeListIterator::New(); this->Parent->GetEdges(eIt); vtkVariantArray *edgeInfo = vtkArrayDownCast( this->Parent->GetEdgeData()->GetAbstractArray("Vertex Ids")); vtkDataArray *vertexInfo = this->Parent->GetVertexData()->GetArray("Vertex Ids"); // avoids double projection int vertexNumber = vertexInfo->GetNumberOfTuples(); std::vector segmentedVertices; do { std::pair, std::vector > superArc; vtkEdgeType e = eIt->Next(); vtkAbstractArray *vertexList = edgeInfo->GetPointer(e.Id)->ToArray(); superArc.first.first = (int) *(vertexInfo->GetTuple(e.Source)); superArc.first.second = (int) *(vertexInfo->GetTuple(e.Target)); superArc.second.resize(vertexList->GetNumberOfTuples()); vertexNumber += vertexList->GetNumberOfTuples(); for(unsigned int i = 0; i < superArc.second.size(); i++) superArc.second[i] = vertexList->GetVariantValue(i).ToInt(); before.push_back(superArc); }while(eIt->HasNext()); segmentedVertices.resize(vertexNumber); for(unsigned int i = 0; i < segmentedVertices.size(); i++) segmentedVertices[i] = false; vtkIdType prevArcId = -1, arcId = 0; while(arcId != prevArcId) { prevArcId = arcId; arcId = GetPreviousArcId(); } prevArcId = -1; while(prevArcId != arcId) { if(this->GetArc(arcId)) { int down, up; down = this->GetNode((this->GetArc(arcId))->NodeId0)->VertexId; up = this->GetNode((this->GetArc(arcId))->NodeId1)->VertexId; std::pair, std::vector > superArc; superArc.first.first = down; superArc.first.second = up; after.push_back(superArc); } prevArcId = arcId; arcId = GetNextArcId(); } std::pair destinationArc; std::map processedOutputArcs; // now map the unsimplified arcs onto the simplified ones for(unsigned int i = 0; i < before.size(); i++) { std::vector simplifiedCriticalNodes; destinationArc = before[i].first; for(unsigned int j = 0; j < this->cancellationHistory.size(); j++) { for(unsigned int k = 0; k < this->cancellationHistory[j].removedArcs.size(); k++) { if((destinationArc.first == this->cancellationHistory[j].removedArcs[k].first) &&(destinationArc.second == this->cancellationHistory[j].removedArcs[k].second)) { // the arc has been involved in a cancellation destinationArc = this->cancellationHistory[j].insertedArcs[0]; if(this->cancellationHistory[j].removedArcs.size() > 1) { if(((this->cancellationHistory[j].removedArcs[0].first == destinationArc.first) &&(this->cancellationHistory[j].removedArcs[1].second == destinationArc.second)) || ((this->cancellationHistory[j].removedArcs[1].first == destinationArc.first) &&(this->cancellationHistory[j].removedArcs[0].second == destinationArc.second))) { for(unsigned int l = 0; l < this->cancellationHistory[j].removedArcs.size(); l++) { if((this->cancellationHistory[j].removedArcs[l].first != destinationArc.first) &&(this->cancellationHistory[j].removedArcs[l].first != destinationArc.second)) { // this critical node will become a degree two node, let's // remember it simplifiedCriticalNodes.push_back( this->cancellationHistory[j].removedArcs[l].first); } if((this->cancellationHistory[j].removedArcs[l].second != destinationArc.first) &&(this->cancellationHistory[j].removedArcs[l].second != destinationArc.second)) { // same thing as above simplifiedCriticalNodes.push_back( this->cancellationHistory[j].removedArcs[l].second); } } } } } } } // at this point the deg2-nodes are in before[i].second // now find the projection in the simplified graph for(unsigned int j = 0; j < after.size(); j++) { if(destinationArc == after[j].first) { std::map::iterator aIt; aIt = processedOutputArcs.find(j); if(aIt == processedOutputArcs.end()) { if(before[i].first == destinationArc) { // non-simplified arc processedOutputArcs[j] = true; after[j].second = before[i].second; } if(before[i].first != destinationArc) { // adding content of before[i].second to after[j].second for(unsigned int k = 0; k < before[i].second.size(); k++) { if(!segmentedVertices[before[i].second[k]]) { after[j].second.push_back(before[i].second[k]); segmentedVertices[before[i].second[k]] = true; } } } for(unsigned int k = 0; k < simplifiedCriticalNodes.size(); k++) { if(!segmentedVertices[simplifiedCriticalNodes[k]]) { after[j].second.push_back(simplifiedCriticalNodes[k]); segmentedVertices[simplifiedCriticalNodes[k]] = true; } } break; } } } } // ensure the sorting on the arcs for(unsigned int i = 0; i < after.size(); i++) { std::vector > scalarValues; for(unsigned int j = 0; j < after[i].second.size(); j++) { std::pair scalarVertex; scalarVertex.first = after[i].second[j]; std::map::iterator sIt; sIt = ScalarField.find(scalarVertex.first); if(sIt != ScalarField.end()) { scalarVertex.second = sIt->second; scalarValues.push_back(scalarVertex); } } std::sort(scalarValues.begin(), scalarValues.end(), vtkReebGraphVertexSoS); for(unsigned int j = 0; j < after[i].second.size(); j++) after[i].second[j] = scalarValues[j].first; } // now construct the vtkMutableDirectedGraph // first, clean up the current graph while(this->Parent->GetNumberOfEdges()) this->Parent->RemoveEdge(0); while(this->Parent->GetNumberOfVertices()) this->Parent->RemoveVertex(0); this->Parent->GetVertexData()->RemoveArray("Vertex Ids"); this->Parent->GetEdgeData()->RemoveArray("Vertex Ids"); vtkIdType prevNodeId = -1, nodeId = 0; while(prevNodeId != nodeId) { prevNodeId = nodeId; nodeId = GetPreviousNodeId(); } prevNodeId = -1; vtkVariantArray *vertexProperties = vtkVariantArray::New(); vertexProperties->SetNumberOfValues(1); vtkIdTypeArray *vertexIds = vtkIdTypeArray::New(); vertexIds->SetName("Vertex Ids"); this->Parent->GetVertexData()->AddArray(vertexIds); std::map vMap; int vIt = 0; while(prevNodeId != nodeId) { vtkIdType nodeVertexId = GetNodeVertexId(nodeId); vMap[nodeVertexId] = vIt; vertexProperties->SetValue(0, nodeVertexId); this->Parent->AddVertex(vertexProperties); prevNodeId = nodeId; nodeId = GetNextNodeId(); vIt++; } vertexIds->Delete(); vertexProperties->Delete(); vtkVariantArray *deg2NodeIds = vtkVariantArray::New(); deg2NodeIds->SetName("Vertex Ids"); this->Parent->GetEdgeData()->AddArray(deg2NodeIds); for(unsigned int i = 0; i < after.size(); i++) { std::map::iterator downIt, upIt; downIt = vMap.find(after[i].first.first); upIt = vMap.find(after[i].first.second); if((downIt != vMap.end())&&(upIt != vMap.end())) { vtkVariantArray *edgeProperties = vtkVariantArray::New(); vtkIdTypeArray *vertexList = vtkIdTypeArray::New(); vertexList->SetNumberOfValues( static_cast(after[i].second.size())); for(unsigned int j = 0; j < after[i].second.size(); j++) vertexList->SetValue(j, after[i].second[j]); edgeProperties->SetNumberOfValues(1); edgeProperties->SetValue(0, vertexList); this->Parent->AddEdge(downIt->second, upIt->second, edgeProperties); vertexList->Delete(); edgeProperties->Delete(); } } deg2NodeIds->Delete(); this->cancellationHistory.clear(); return 0; } //---------------------------------------------------------------------------- int vtkReebGraph::Simplify(double simplificationThreshold, vtkReebGraphSimplificationMetric *simplificationMetric) { int deletionNumber = 0; this->Storage->cancellationHistory.clear(); this->Storage->historyOn = true; this->Storage->ArcNumber = 0; this->Storage->NodeNumber = 0; deletionNumber = this->Storage->SimplifyBranches( simplificationThreshold, simplificationMetric) + this->Storage->SimplifyLoops( simplificationThreshold, simplificationMetric) + this->Storage->SimplifyBranches( simplificationThreshold, simplificationMetric); this->Storage->historyOn = false; return deletionNumber; } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::FlushLabels() { for (int A=1;AMainArcTable.Size;A++) { if (!(this->GetArc(A)->LabelId1 == ((int)-2))) this->GetArc(A)->LabelId0 = this->GetArc(A)->LabelId1=0; } if (this->MainLabelTable.Buffer) { free(this->MainLabelTable.Buffer); } this->MainLabelTable.Buffer=(vtkReebLabel*)malloc(sizeof(vtkReebLabel)*2); this->MainLabelTable.Size=2; this->MainLabelTable.Number=1; this->MainLabelTable.FreeZone=1; this->GetLabel(1)->HNext = ((int)-2); this->GetLabel(1)->ArcId = 0; } //---------------------------------------------------------------------------- void vtkReebGraph::DeepCopy(vtkDataObject *src) { vtkReebGraph *srcG = vtkReebGraph::SafeDownCast(src); if (srcG) { this->Storage->DeepCopy(srcG->Storage); } vtkMutableDirectedGraph::DeepCopy(srcG); } //---------------------------------------------------------------------------- void vtkReebGraph::Set(vtkMutableDirectedGraph *g) { vtkMutableDirectedGraph::DeepCopy(g); } //---------------------------------------------------------------------------- void vtkReebGraph::CloseStream() { vtkIdType prevArcId = -1, arcId = 0; while(arcId != prevArcId) { prevArcId = arcId; arcId = this->Storage->GetPreviousArcId(); } prevArcId = -1; // loop over the arcs and build the local adjacency map // vertex -> (down vertices, up vertices) std::map, std::vector > > localAdjacency; while(prevArcId != arcId) { vtkIdType downVertexId, upVertexId; downVertexId = this->Storage->GetNode((this->Storage->GetArc(arcId))->NodeId0)->VertexId; upVertexId = this->Storage->GetNode((this->Storage->GetArc(arcId))->NodeId1)->VertexId; std::map, std::vector > >::iterator aIt; // lookUp for the down vertex aIt = localAdjacency.find(downVertexId); if(aIt == localAdjacency.end()) { std::pair, std::vector > adjacencyItem; adjacencyItem.second.push_back(upVertexId); localAdjacency[downVertexId] = adjacencyItem; } else { aIt->second.second.push_back(upVertexId); } // same thing for the up vertex aIt = localAdjacency.find(upVertexId); if(aIt == localAdjacency.end()) { std::pair, std::vector > adjacencyItem; adjacencyItem.first.push_back(downVertexId); localAdjacency[upVertexId] = adjacencyItem; } else { aIt->second.first.push_back(downVertexId); } prevArcId = arcId; arcId = this->Storage->GetNextArcId(); } // now build the super-arcs with deg-2 nodes // , (arc, deg2 node list) std::vector, std::vector > > globalAdjacency; std::map, std::vector > >::iterator aIt; aIt = localAdjacency.begin(); do { if(!((aIt->second.first.size() == 1)&&(aIt->second.second.size() == 1))) { // not a deg-2 node if(!aIt->second.second.empty()) { // start the sweep up for(unsigned int i = 0; i < aIt->second.second.size(); i++) { std::vector deg2List; std::map, std::vector > >::iterator nextIt; nextIt = localAdjacency.find(aIt->second.second[i]); while((nextIt->second.first.size() == 1) &&(nextIt->second.second.size() == 1)) { deg2List.push_back(nextIt->first); nextIt = localAdjacency.find(nextIt->second.second[0]); } globalAdjacency.push_back( std::pair, std::vector >(std::pair( aIt->first, nextIt->first), deg2List)); } } } ++aIt; } while(aIt != localAdjacency.end()); // now cleanup the internal representation int nmyend=0; for (vtkIdType N=1;NStorage->MainNodeTable.Size;N++) { // clear the node if (this->Storage->GetNode(N)->ArcUpId == ((int)-2)) continue; vtkReebGraph::Implementation::vtkReebNode* n = this->Storage->GetNode(N); if (!n->IsFinalized) { nmyend++; this->Storage->EndVertex(N); } } this->Storage->FlushLabels(); // now construct the actual graph vtkIdType prevNodeId = -1, nodeId = 0; while(prevNodeId != nodeId) { prevNodeId = nodeId; nodeId = this->Storage->GetPreviousNodeId(); } prevNodeId = -1; vtkVariantArray *vertexProperties = vtkVariantArray::New(); vertexProperties->SetNumberOfValues(1); vtkIdTypeArray *vertexIds = vtkIdTypeArray::New(); vertexIds->SetName("Vertex Ids"); GetVertexData()->AddArray(vertexIds); std::map vMap; int vIt = 0; while(prevNodeId != nodeId) { vtkIdType nodeVertexId = this->Storage->GetNodeVertexId(nodeId); vMap[nodeVertexId] = vIt; vertexProperties->SetValue(0, nodeVertexId); AddVertex(vertexProperties); prevNodeId = nodeId; nodeId = this->Storage->GetNextNodeId(); vIt++; } vertexIds->Delete(); vertexProperties->Delete(); vtkVariantArray *deg2NodeIds = vtkVariantArray::New(); deg2NodeIds->SetName("Vertex Ids"); GetEdgeData()->AddArray(deg2NodeIds); for(unsigned int i = 0; i < globalAdjacency.size(); i++) { std::map::iterator downIt, upIt; downIt = vMap.find(globalAdjacency[i].first.first); upIt = vMap.find(globalAdjacency[i].first.second); if((downIt != vMap.end())&&(upIt != vMap.end())) { vtkVariantArray *edgeProperties = vtkVariantArray::New(); vtkIdTypeArray *vertexList = vtkIdTypeArray::New(); vertexList->SetNumberOfValues( static_cast(globalAdjacency[i].second.size())); for(unsigned int j = 0; j < globalAdjacency[i].second.size(); j++) vertexList->SetValue(j, globalAdjacency[i].second[j]); edgeProperties->SetNumberOfValues(1); edgeProperties->SetValue(0, vertexList); AddEdge(downIt->second, upIt->second, edgeProperties); vertexList->Delete(); edgeProperties->Delete(); } } deg2NodeIds->Delete(); } //---------------------------------------------------------------------------- vtkReebGraph::vtkReebGraph() { this->Storage = new vtkReebGraph::Implementation; this->Storage->Parent = this; } //---------------------------------------------------------------------------- vtkReebGraph::~vtkReebGraph() { delete this->Storage; } //---------------------------------------------------------------------------- void vtkReebGraph::PrintSelf(ostream& os, vtkIndent indent) { vtkObject::PrintSelf(os, indent); os << indent << "Reeb graph general statistics:" << endl; os << indent << indent << "Number Of Node(s): " << this->Storage->GetNumberOfNodes() << endl; os << indent << indent << "Number Of Arc(s): " << this->Storage->GetNumberOfArcs() << endl; os << indent << indent << "Number Of Connected Component(s): " << this->Storage->GetNumberOfConnectedComponents() << endl; os << indent << indent << "Number Of Loop(s): " << this->Storage->GetNumberOfLoops() << endl; } void vtkReebGraph::PrintNodeData(ostream& os, vtkIndent indent) { vtkIdType arcId = 0, nodeId = 0; os << indent << "Node Data:" << endl; vtkIdType prevNodeId = -1; // roll back to the beginning of the list while(prevNodeId != nodeId){ prevNodeId = nodeId; nodeId = this->Storage->GetPreviousNodeId(); } prevNodeId = -1; while(prevNodeId != nodeId) { prevNodeId = nodeId; vtkIdList *downArcIdList = vtkIdList::New(); vtkIdList *upArcIdList = vtkIdList::New(); this->Storage->GetNodeDownArcIds(nodeId, downArcIdList); this->Storage->GetNodeUpArcIds(nodeId, upArcIdList); cout << indent << indent << "Node " << nodeId << ":" << endl; cout << indent << indent << indent; cout << "Vert: " << this->Storage->GetNodeVertexId(nodeId); cout << ", Val: " << this->Storage->GetNodeScalarValue(nodeId); cout << ", DwA:"; for(vtkIdType i = 0; i < downArcIdList->GetNumberOfIds(); i++) cout << " " << this->Storage->GetArcDownNodeId(downArcIdList->GetId(i)); cout << ", UpA:"; for(vtkIdType i = 0; i < upArcIdList->GetNumberOfIds(); i++) cout << " " << this->Storage->GetArcUpNodeId(upArcIdList->GetId(i)); cout << endl; downArcIdList->Delete(); upArcIdList->Delete(); nodeId = this->Storage->GetNextNodeId(); } os << indent << "Arc Data:" << endl; vtkIdType prevArcId = -1; arcId = 0; // roll back to the beginning of the list while(prevArcId != arcId){ prevArcId = arcId; arcId = this->Storage->GetPreviousArcId(); } prevArcId = -1; while(prevArcId != arcId) { prevArcId = arcId; cout << indent << indent << "Arc " << arcId << ":" << endl; cout << indent << indent << indent; cout << "Down: " << this->Storage->GetArcDownNodeId(arcId); cout << ", Up: " << this->Storage->GetArcUpNodeId(arcId); cout << ", Persistence: " << this->Storage->GetNodeScalarValue(this->Storage->GetArcUpNodeId(arcId)) - this->Storage->GetNodeScalarValue( this->Storage->GetArcDownNodeId(arcId)); cout << endl; arcId = this->Storage->GetNextArcId(); } } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::GetNodeDownArcIds(vtkIdType nodeId, vtkIdList *arcIdList) { vtkIdType i = 0; if(!arcIdList) return; arcIdList->Reset(); for(vtkIdType arcId = this->GetNode(nodeId)->ArcDownId; arcId; arcId = this->GetArc(arcId)->ArcDwId1) { arcIdList->InsertId(i, arcId); i++; } } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::GetNodeUpArcIds(vtkIdType nodeId, vtkIdList *arcIdList) { vtkIdType i = 0; if(!arcIdList) return; for(vtkIdType arcId = this->GetNode(nodeId)->ArcUpId; arcId; arcId = this->GetArc(arcId)->ArcDwId0) { arcIdList->InsertId(i, arcId); i++; } } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::FindLoops() { if (this->ArcLoopTable) { free(this->ArcLoopTable); this->ArcLoopTable=nullptr; this->LoopNumber=0; } this->ConnectedComponentNumber=0; int nstack=0,mstack=0; int* stack=nullptr; char* Ntouch=(char*)malloc(sizeof(char)*this->MainNodeTable.Size); char* Atouch=(char*)malloc(sizeof(char)*this->MainArcTable.Size); memset(Ntouch,0,sizeof(char)*this->MainNodeTable.Size); for(int Node=1;NodeMainNodeTable.Size;Node++) { // check that the node is clear if (this->GetNode(Node)->ArcUpId == ((int)-2)) continue; if (!Ntouch[Node]) { ++(this->ConnectedComponentNumber); memset(Atouch,0,sizeof(bool)*this->MainArcTable.Size); Ntouch[Node]=1; nstack=0; vtkReebGraphStackPush(Node); while (vtkReebGraphStackSize()) { int N=vtkReebGraphStackTop(); vtkReebGraphStackPop(); for (int dir=0;dir<=1;dir++) { for (int A = (!dir) ? (this->GetNode(N)->ArcDownId) : (this->GetNode(N)->ArcUpId); A; A = (!dir) ? (this->GetArc(A)->ArcDwId1) : (this->GetArc(A)->ArcDwId0)) { int M = (!dir) ? (this->GetArc(A)->NodeId0) : (this->GetArc(A)->NodeId1); if (Atouch[A]) continue; if (!Ntouch[M]) { vtkReebGraphStackPush(M); } else { this->LoopNumber++; this->ArcLoopTable = (vtkIdType *) realloc(this->ArcLoopTable, sizeof(vtkIdType)*this->LoopNumber); this->ArcLoopTable[this->LoopNumber-1]=A; } Atouch[A]=1; Ntouch[M]=1; } } } } } free(stack); free(Ntouch); free(Atouch); } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::AddMeshVertex(vtkIdType vertexId, double scalar) { static bool firstVertex = true; ScalarField[vertexId] = scalar; vtkIdType N0; ResizeMainNodeTable(1); //create a new node in the graph... N0 = this->MainNodeTable.FreeZone; this->MainNodeTable.FreeZone = this->GetNode(N0)->ArcDownId; ++(this->MainNodeTable.Number); memset(this->GetNode(N0),0,sizeof(vtkReebNode)); vtkReebNode* node = this->GetNode(N0); node->VertexId=vertexId; node->Value = scalar; node->ArcDownId=0; node->ArcUpId=0; node->IsFinalized = false; if(firstVertex) { this->MinimumScalarValue = node->Value; this->MaximumScalarValue = node->Value; } else { if(node->Value > this->MaximumScalarValue) this->MaximumScalarValue = node->Value; if(node->Value < this->MinimumScalarValue) this->MinimumScalarValue = node->Value; } firstVertex = false; return N0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindDwLabel(vtkIdType nodeId, vtkReebLabelTag label) { for (vtkIdType arcId = this->GetNode(nodeId)->ArcDownId; arcId; arcId = this->GetArc(arcId)->ArcDwId1) { for (vtkIdType labelId = this->GetArc(arcId)->LabelId0; labelId; labelId = this->GetLabel(labelId)->HNext) { if (this->GetLabel(labelId)->label == label) return labelId; } } return 0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::FindUpLabel(vtkIdType nodeId, vtkReebLabelTag label) { for (vtkIdType arcId = this->GetNode(nodeId)->ArcUpId; arcId; arcId = this->GetArc(arcId)->ArcDwId0) { for (vtkIdType labelId = this->GetArc(arcId)->LabelId0; labelId; labelId = this->GetLabel(labelId)->HNext) { if (this->GetLabel(labelId)->label==label) return labelId; } } return 0; } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::ResizeMainArcTable(int newSize) { int oldsize,i; if ((this->MainArcTable.Size-this->MainArcTable.Number)< newSize) { oldsize=this->MainArcTable.Size; if (!this->MainArcTable.Size) this->MainArcTable.Size= newSize; while ((this->MainArcTable.Size-this->MainArcTable.Number)< newSize) this->MainArcTable.Size<<=1; this->MainArcTable.Buffer = (vtkReebArc*)realloc(this->MainArcTable.Buffer, sizeof(vtkReebArc)*this->MainArcTable.Size); for (i=oldsize;iMainArcTable.Size-1;i++) { this->GetArc(i)->LabelId0 = i+1; // clear arc this->GetArc(i)->LabelId1 = ((int)-2); } this->GetArc(i)->LabelId0 = this->MainArcTable.FreeZone; // clear arc this->GetArc(i)->LabelId1 = ((int)-2); this->MainArcTable.FreeZone=oldsize; } } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::ResizeMainLabelTable(int newSize) { int oldsize,i; if ((this->MainLabelTable.Size-this->MainLabelTable.Number)< newSize) { oldsize=this->MainLabelTable.Size; if (!this->MainLabelTable.Size) this->MainLabelTable.Size = newSize; while ((this->MainLabelTable.Size-this->MainLabelTable.Number)< newSize) this->MainLabelTable.Size<<=1; this->MainLabelTable.Buffer = (vtkReebLabel*)realloc(this->MainLabelTable.Buffer, sizeof(vtkReebLabel)*this->MainLabelTable.Size); for (i=oldsize;iMainLabelTable.Size-1;i++) { this->GetLabel(i)->ArcId = i+1; this->GetLabel(i)->HNext = ((int)-2); } this->GetLabel(i)->ArcId = this->MainLabelTable.FreeZone; this->GetLabel(i)->HNext = ((int)-2); this->MainLabelTable.FreeZone=oldsize; } } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::AddPath(int nodeNumber, vtkIdType* nodeOffset, vtkReebLabelTag label) { vtkIdType i, Lprev, Ret=0; this->ResizeMainArcTable(nodeNumber - 1); if (label) ResizeMainLabelTable(nodeNumber - 1); Lprev=0; for (i = 0; i < (nodeNumber - 1);i++) { vtkIdType N0 = nodeOffset[i ]; vtkIdType N1= nodeOffset[i + 1]; //create a new arc in the graph int A = this->MainArcTable.FreeZone; this->MainArcTable.FreeZone = this->GetArc(A)->LabelId0; ++(this->MainArcTable.Number); memset(this->GetArc(A),0,sizeof(vtkReebArc)); vtkReebArc* arc = this->GetArc(A); int L=0; if (!Ret) Ret=A; if (label) { vtkReebLabel* temporaryLabel; //create a new label in the graph L = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone = this->GetLabel(L)->ArcId; ++(this->MainLabelTable.Number); memset(this->GetLabel(L),0,sizeof(vtkReebLabel)); temporaryLabel = this->GetLabel(L); temporaryLabel->ArcId = A; temporaryLabel->label=label; temporaryLabel->VPrev=Lprev; } arc->NodeId0=N0; arc->NodeId1=N1; arc->LabelId0=arc->LabelId1=L; vtkReebGraphAddUpArc(this,N0,A); vtkReebGraphAddDownArc(this,N1,A); if (label) { if (Lprev) this->GetLabel(Lprev)->VNext = L; Lprev=L; } } return Ret; } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::Collapse(vtkIdType startingNode, vtkIdType endingNode, vtkReebLabelTag startingLabel, vtkReebLabelTag endingLabel) { int L0,L0n,L1,L1n; int cont[3]={0,0,0},Case; if (startingNode == endingNode) return; vtkReebNode* nstart = this->GetNode(startingNode); vtkReebNode* nend = this->GetNode(endingNode); if (!vtkReebGraphIsSmaller(this,startingNode,endingNode,nstart,nend)) { vtkReebGraphSwapVars(int,startingNode,endingNode); vtkReebGraphSwapVars(vtkReebNode* ,nstart,nend); } L0 = FindUpLabel(startingNode, startingLabel); L1 = FindUpLabel(startingNode, endingLabel); while (1) { int A0 = this->GetLabel(L0)->ArcId; vtkReebArc* a0 = this->GetArc(A0); int A1 = this->GetLabel(L1)->ArcId; vtkReebArc* a1 = this->GetArc(A1); vtkReebNode *down0 = this->GetNode(a0->NodeId0); vtkReebNode *up0 = this->GetNode(a0->NodeId1); vtkReebNode *up1 = this->GetNode(a1->NodeId1); /* it is the same arc, no semplification is done */ if (A0==A1) { Case = 0; L0n = this->GetLabel(L0)->VNext; L1n = this->GetLabel(L1)->VNext; } /* there are two arcs connecting the same start-end node */ else if (A0 != A1 && a0->NodeId1 == a1->NodeId1) { Case = 1; vtkReebGraphRemoveUpArc(this, a0->NodeId0, A1); vtkReebGraphRemoveDownArc(this, a0->NodeId1, A1); for (int Lcur = this->GetArc(A1)->LabelId0; Lcur; Lcur = this->GetLabel(Lcur)->HNext) { this->GetLabel(Lcur)->ArcId = A0; } this->GetLabel(this->GetArc(A1)->LabelId0)->HPrev = this->GetArc(A0)->LabelId1; this->GetLabel(this->GetArc(A0)->LabelId1)->HNext = this->GetArc(A1)->LabelId0; this->GetArc(A0)->LabelId1 = this->GetArc(A1)->LabelId1; this->GetArc(A1)->LabelId0=0; this->GetArc(A1)->LabelId1=0; //delete the arc from the graph... this->GetArc(A1)->LabelId1 = ((int)-2); this->GetArc(A1)->LabelId0 = this->MainArcTable.FreeZone; this->MainArcTable.FreeZone=(A1); --(this->MainArcTable.Number); L0n = this->GetLabel(L0)->VNext; L1n = this->GetLabel(L1)->VNext; } else { if(historyOn) { vtkReebCancellation c; int downVertex, middleVertex, upVertex; downVertex = down0->VertexId; middleVertex = up0->VertexId; upVertex = up1->VertexId; c.removedArcs.push_back(std::pair(downVertex, upVertex)); c.insertedArcs.push_back(std::pair(downVertex, middleVertex)); c.insertedArcs.push_back(std::pair(middleVertex, upVertex)); this->cancellationHistory.push_back(c); } // a more complicate situation, collapse reaching the less ending point of // the arcs. Case=2; { vtkReebNode* a0n1 = this->GetNode(a0->NodeId1); vtkReebNode* a1n1 = this->GetNode(a1->NodeId1); if (!vtkReebGraphIsSmaller(this,a0->NodeId1,a1->NodeId1,a0n1,a1n1)) { vtkReebGraphSwapVars(int,A0,A1); vtkReebGraphSwapVars(int,L0,L1); vtkReebGraphSwapVars(vtkReebArc* ,a0,a1); } } vtkReebGraphRemoveUpArc(this,a0->NodeId0,A1); a1->NodeId0=a0->NodeId1; vtkReebGraphAddUpArc(this,a0->NodeId1,A1); //"replicate" labels from A1 to A0 for (int Lcur = this->GetArc(A1)->LabelId0; Lcur;Lcur = this->GetLabel(Lcur)->HNext) { int Lnew; ResizeMainLabelTable(1); //create a new label in the graph Lnew = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone = this->GetLabel(Lnew)->ArcId; ++(this->MainLabelTable.Number); memset(this->GetLabel(Lnew),0,sizeof(vtkReebLabel)); vtkReebLabel* lnew = this->GetLabel(Lnew); vtkReebLabel* lcur = this->GetLabel(Lcur); lnew->ArcId = A0; lnew->VPrev = lcur->VPrev; if (lcur->VPrev) this->GetLabel(lcur->VPrev)->VNext=Lnew; lcur->VPrev = Lnew; lnew->VNext = Lcur; lnew->label = lcur->label; lnew->HNext = 0; lnew->HPrev = this->GetArc(A0)->LabelId1; this->GetLabel(this->GetArc(A0)->LabelId1)->HNext = Lnew; this->GetArc(A0)->LabelId1=Lnew; } L0n = this->GetLabel(L0)->VNext; L1n=L1; } ++cont[Case]; int N0=a0->NodeId0; vtkReebNode* n0 = this->GetNode(N0); if (n0->IsFinalized && vtkReebGraphIsRegular(this,n0)) { if(historyOn) { vtkReebArc *up = this->GetArc(n0->ArcUpId), *down = this->GetArc(n0->ArcDownId); vtkReebCancellation c; int v0, v1, v2, v3; v0 = this->GetNode(up->NodeId0)->VertexId; v1 = this->GetNode(up->NodeId1)->VertexId; v2 = this->GetNode(down->NodeId0)->VertexId; v3 = this->GetNode(down->NodeId1)->VertexId; c.removedArcs.push_back(std::pair(v0, v1)); c.removedArcs.push_back(std::pair(v2, v3)); c.insertedArcs.push_back(std::pair(v2, v1)); this->cancellationHistory.push_back(c); } this->CollapseVertex(N0, n0); } /* end condition */ if (a0->NodeId1 == endingNode) { vtkReebNode* nendNode = this->GetNode(endingNode); if (nendNode->IsFinalized && vtkReebGraphIsRegular(this, nendNode)) { if(historyOn) { vtkReebArc *up = this->GetArc(this->GetNode(endingNode)->ArcUpId), *down = this->GetArc(this->GetNode(endingNode)->ArcDownId); vtkReebCancellation c; int v0, v1, v2, v3; v0 = this->GetNode(up->NodeId0)->VertexId; v1 = this->GetNode(up->NodeId1)->VertexId; v2 = this->GetNode(down->NodeId0)->VertexId; v3 = this->GetNode(down->NodeId1)->VertexId; c.removedArcs.push_back(std::pair(v0, v1)); c.removedArcs.push_back(std::pair(v2, v3)); c.insertedArcs.push_back(std::pair(v2, v1)); this->cancellationHistory.push_back(c); } this->CollapseVertex(endingNode, nendNode); } return; } L0 = L0n; L1 = L1n; } } void vtkReebGraph::Implementation::SimplifyLabels(const vtkIdType nodeId, vtkReebLabelTag onlyLabel, bool goDown, bool goUp) { static int nactivation=0; ++nactivation; int A,L,Lnext; vtkReebLabel *l; vtkReebNode *n = this->GetNode(nodeId); //I remove all Labels (paths) which start from me if (goDown) { int Anext; for (A=n->ArcDownId;A;A=Anext) { Anext = this->GetArc(A)->ArcDwId1; for (L = this->GetArc(A)->LabelId0;L;L=Lnext) { Lnext = this->GetLabel(L)->HNext; if (!(l = this->GetLabel(L))->VNext) //...starts from me! { if (!onlyLabel || onlyLabel == this->GetLabel(L)->label) { int Lprev; for (int Lcur=L;Lcur;Lcur=Lprev) { vtkReebLabel* lcur = this->GetLabel(Lcur); Lprev=lcur->VPrev; int CurA=lcur->ArcId; if (lcur->HPrev) this->GetLabel(lcur->HPrev)->HNext = lcur->HNext; else this->GetArc(CurA)->LabelId0 = lcur->HNext; if (lcur->HNext) this->GetLabel(lcur->HNext)->HPrev = lcur->HPrev; else this->GetArc(CurA)->LabelId1 = lcur->HPrev; //delete the label this->GetLabel(Lcur)->HNext = ((int)-2); this->GetLabel(Lcur)->ArcId = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone=(Lcur); --(this->MainLabelTable.Number); } } } } } } // Remove all Labels (paths) which start from here if (goUp && !(this->GetNode(nodeId)->ArcUpId == ((int)-2))) { int Anext; for (A=n->ArcUpId;A;A=Anext) { Anext = this->GetArc(A)->ArcDwId0; for (L=this->GetArc(A)->LabelId0;L;L=Lnext) { Lnext = this->GetLabel(L)->HNext; if (!(l = this->GetLabel(L))->VPrev) //...starts from me! { if (!onlyLabel || onlyLabel == this->GetLabel(L)->label) { int myLnext; for (int Lcur = L; Lcur; Lcur = myLnext) { vtkReebLabel* lcur = this->GetLabel(Lcur); myLnext = lcur->VNext; int CurA = lcur->ArcId; vtkReebArc* cura = this->GetArc(CurA); if (lcur->HPrev) { this->GetLabel(lcur->HPrev)->HNext = lcur->HNext; } else { cura->LabelId0=lcur->HNext; } if (lcur->HNext) { this->GetLabel(lcur->HNext)->HPrev = lcur->HPrev; } else { cura->LabelId1=lcur->HPrev; } //delete the label... this->GetLabel(Lcur)->HNext = ((int)-2); this->GetLabel(Lcur)->ArcId = this->MainLabelTable.FreeZone; this->MainLabelTable.FreeZone=(Lcur); --(this->MainLabelTable.Number); } } } } } } } //---------------------------------------------------------------------------- void vtkReebGraph::Implementation::EndVertex(const vtkIdType N) { vtkReebNode *n = this->GetNode(N); n->IsFinalized = true; if (!(this->GetNode(N)->ArcUpId == ((int)-2))) { this->SimplifyLabels(N); if (!(this->GetNode(N)->ArcUpId == ((int)-2))) { //special case for regular point. A node is regular if it has one //arc down and one arc up. In this case it can disappear if (vtkReebGraphIsRegular(this,n)) { this->CollapseVertex(N, n); } } } } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::AddMeshTetrahedron(vtkIdType vertex0Id, double f0, vtkIdType vertex1Id, double f1, vtkIdType vertex2Id, double f2, vtkIdType vertex3Id, double f3) { vtkIdType vertex0, vertex1, vertex2, vertex3; vertex0 = this->VertexStream[vertex0Id]; vertex1 = this->VertexStream[vertex1Id]; vertex2 = this->VertexStream[vertex2Id]; vertex3 = this->VertexStream[vertex3Id]; int N0 = this->VertexMap[vertex0]; int N1 = this->VertexMap[vertex1]; int N2 = this->VertexMap[vertex2]; int N3 = this->VertexMap[vertex3]; // Consistency less check if (f3 < f2 || (f3==f2 && vertex3 < vertex2)) { vtkReebGraphSwapVars(int,vertex2,vertex3); vtkReebGraphSwapVars(int,N2,N3); vtkReebGraphSwapVars(double,f2,f3); } if (f2 < f1 || (f2==f1 && vertex2 < vertex1)) { vtkReebGraphSwapVars(int,vertex1,vertex2); vtkReebGraphSwapVars(int,N1,N2); vtkReebGraphSwapVars(double,f1,f2); } if (f1 < f0 || (f1==f0 && vertex1 < vertex0)) { vtkReebGraphSwapVars(int,vertex0,vertex1); vtkReebGraphSwapVars(int,N0,N1); vtkReebGraphSwapVars(double,f0,f1); } if (f3 < f2 || (f3==f2 && vertex3 < vertex2)) { vtkReebGraphSwapVars(int,vertex2,vertex3); vtkReebGraphSwapVars(int,N2,N3); vtkReebGraphSwapVars(double,f2,f3); } if (f2 < f1 || (f2==f1 && vertex2 < vertex1)) { vtkReebGraphSwapVars(int,vertex1,vertex2); vtkReebGraphSwapVars(int,N1,N2); vtkReebGraphSwapVars(double,f1,f2); } if (f3 < f2 || (f3==f2 && vertex3 < vertex2)) { vtkReebGraphSwapVars(int,vertex2,vertex3); vtkReebGraphSwapVars(int,N2,N3); vtkReebGraphSwapVars(double,f2,f3); } vtkIdType t0[]={vertex0, vertex1, vertex2}, t1[]={vertex0, vertex1, vertex3}, t2[]={vertex0, vertex2, vertex3}, t3[]={vertex1, vertex2, vertex3}; vtkIdType *cellIds[4]; cellIds[0] = t0; cellIds[1] = t1; cellIds[2] = t2; cellIds[3] = t3; for(int i=0; i < 3; i++) { int n0 = this->VertexMap[cellIds[i][0]], n1 = this->VertexMap[cellIds[i][1]], n2 = this->VertexMap[cellIds[i][2]]; vtkReebLabelTag Label01 = ((vtkReebLabelTag) cellIds[i][0]) | (((vtkReebLabelTag) cellIds[i][1])<<32); vtkReebLabelTag Label12 = ((vtkReebLabelTag) cellIds[i][1]) | (((vtkReebLabelTag) cellIds[i][2])<<32); vtkReebLabelTag Label02 = ((vtkReebLabelTag) cellIds[i][0]) | (((vtkReebLabelTag) cellIds[i][2])<<32); if (!this->FindUpLabel(n0,Label01)) { vtkIdType N01[] = {n0, n1}; this->AddPath(2, N01, Label01); } if (!this->FindUpLabel(n1,Label12)) { vtkIdType N12[] = {n1,n2}; this->AddPath(2, N12, Label12); } if (!this->FindUpLabel(n0, Label02)) { vtkIdType N02[] = {n0,n2}; this->AddPath(2, N02, Label02); } this->Collapse(n0,n1,Label01,Label02); this->Collapse(n1,n2,Label12,Label02); } if (!(--(this->TriangleVertexMap[vertex0]))) this->EndVertex(N0); if (!(--(this->TriangleVertexMap[vertex1]))) this->EndVertex(N1); if (!(--(this->TriangleVertexMap[vertex2]))) this->EndVertex(N2); if (!(--(this->TriangleVertexMap[vertex3]))) this->EndVertex(N3); return 1; } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::AddMeshTriangle(vtkIdType vertex0Id, double f0, vtkIdType vertex1Id, double f1, vtkIdType vertex2Id, double f2) { int vertex0 = this->VertexStream[vertex0Id], vertex1 = this->VertexStream[vertex1Id], vertex2 = this->VertexStream[vertex2Id]; int N0 = this->VertexMap[vertex0]; int N1 = this->VertexMap[vertex1]; int N2 = this->VertexMap[vertex2]; // Consistency less check if (f2 < f1 || (f2==f1 && vertex2 < vertex1)) { vtkReebGraphSwapVars(int,vertex1,vertex2); vtkReebGraphSwapVars(int,N1,N2); vtkReebGraphSwapVars(double,f1,f2); } if (f1 < f0 || (f1==f0 && vertex1 < vertex0)) { vtkReebGraphSwapVars(int,vertex0,vertex1); vtkReebGraphSwapVars(int,N0,N1); vtkReebGraphSwapVars(double,f0,f1); } if (f2 < f1 || (f2==f1 && vertex2 < vertex1)) { vtkReebGraphSwapVars(int,vertex1,vertex2); vtkReebGraphSwapVars(int,N1,N2); vtkReebGraphSwapVars(double,f1,f2); } vtkReebLabelTag Label01 = ((vtkReebLabelTag)vertex0) | (((vtkReebLabelTag)vertex1)<<32); vtkReebLabelTag Label12 = ((vtkReebLabelTag)vertex1) | (((vtkReebLabelTag)vertex2)<<32); vtkReebLabelTag Label02 = ((vtkReebLabelTag)vertex0) | (((vtkReebLabelTag)vertex2)<<32); if (!this->FindUpLabel(N0,Label01)) { vtkIdType N01[] = {N0, N1}; this->AddPath(2, N01, Label01); } if (!this->FindUpLabel(N1,Label12)) { vtkIdType N12[] = {N1,N2}; this->AddPath(2, N12, Label12); } if (!this->FindUpLabel(N0, Label02)) { vtkIdType N02[] = {N0,N2}; this->AddPath(2, N02, Label02); } this->Collapse(N0,N1,Label01,Label02); this->Collapse(N1,N2,Label12,Label02); if (!(--(this->TriangleVertexMap[vertex0]))) this->EndVertex(N0); if (!(--(this->TriangleVertexMap[vertex1]))) this->EndVertex(N1); if (!(--(this->TriangleVertexMap[vertex2]))) this->EndVertex(N2); return 1; } //---------------------------------------------------------------------------- int vtkReebGraph::StreamTetrahedron( vtkIdType vertex0Id, double scalar0, vtkIdType vertex1Id, double scalar1, vtkIdType vertex2Id, double scalar2, vtkIdType vertex3Id, double scalar3) { return this->Storage->StreamTetrahedron(vertex0Id, scalar0, vertex1Id, scalar1, vertex2Id, scalar2, vertex3Id, scalar3); } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::StreamTetrahedron( vtkIdType vertex0Id, double scalar0, vtkIdType vertex1Id, double scalar1, vtkIdType vertex2Id, double scalar2, vtkIdType vertex3Id, double scalar3) { if(!this->VertexMapAllocatedSize) { // first allocate an arbitrary size this->VertexMapAllocatedSize = vtkReebGraphInitialStreamSize; this->VertexMap = (vtkIdType *) malloc( sizeof(vtkIdType)*this->VertexMapAllocatedSize); memset(this->VertexMap, 0, sizeof(vtkIdType)*this->VertexMapAllocatedSize); this->VertexStream.clear(); } else if(this->VertexMapSize >= this->VertexMapAllocatedSize - 4) { int oldSize = this->VertexMapAllocatedSize; this->VertexMapAllocatedSize <<= 1; this->VertexMap = (vtkIdType *) realloc(this->VertexMap, sizeof(vtkIdType)*this->VertexMapAllocatedSize); for(int i = oldSize; i < this->VertexMapAllocatedSize - 1; i++) this->VertexMap[i] = 0; } // same thing with the triangle map if(!this->TriangleVertexMapAllocatedSize) { // first allocate an arbitrary size this->TriangleVertexMapAllocatedSize = vtkReebGraphInitialStreamSize; this->TriangleVertexMap = (int *) malloc( sizeof(int)*this->TriangleVertexMapAllocatedSize); memset(this->TriangleVertexMap, 0, sizeof(int)*this->TriangleVertexMapAllocatedSize); } else if(this->TriangleVertexMapSize >= this->TriangleVertexMapAllocatedSize - 4) { int oldSize = this->TriangleVertexMapAllocatedSize; this->TriangleVertexMapAllocatedSize <<= 1; this->TriangleVertexMap = (int *) realloc(this->TriangleVertexMap, sizeof(int)*this->TriangleVertexMapAllocatedSize); for(int i = oldSize; i < this->TriangleVertexMapAllocatedSize - 1; i++) this->TriangleVertexMap[i] = 0; } // Add the vertices to the stream std::map::iterator sIter; // vertex0 sIter = this->VertexStream.find(vertex0Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex0Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex0Id, scalar0); this->VertexMapSize++; this->TriangleVertexMapSize++; } // vertex1 sIter = this->VertexStream.find(vertex1Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex1Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex1Id, scalar1); this->VertexMapSize++; this->TriangleVertexMapSize++; } // vertex2 sIter = this->VertexStream.find(vertex2Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex2Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex2Id, scalar2); this->VertexMapSize++; this->TriangleVertexMapSize++; } // vertex3 sIter = this->VertexStream.find(vertex3Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex3Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex3Id, scalar3); this->VertexMapSize++; this->TriangleVertexMapSize++; } this->AddMeshTetrahedron(vertex0Id, scalar0, vertex1Id, scalar1, vertex2Id, scalar2, vertex3Id, scalar3); return 0; } //---------------------------------------------------------------------------- int vtkReebGraph::StreamTriangle( vtkIdType vertex0Id, double scalar0, vtkIdType vertex1Id, double scalar1, vtkIdType vertex2Id, double scalar2) { return this->Storage->StreamTriangle(vertex0Id, scalar0, vertex1Id, scalar1, vertex2Id, scalar2); } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::StreamTriangle(vtkIdType vertex0Id, double scalar0, vtkIdType vertex1Id, double scalar1, vtkIdType vertex2Id, double scalar2) { if(!this->VertexMapAllocatedSize) { // first allocate an arbitrary size this->VertexMapAllocatedSize = vtkReebGraphInitialStreamSize; this->VertexMap = (vtkIdType *) malloc( sizeof(vtkIdType)*this->VertexMapAllocatedSize); memset(this->VertexMap, 0, sizeof(vtkIdType)*this->VertexMapAllocatedSize); } else if(this->VertexMapSize >= this->VertexMapAllocatedSize - 3) { int oldSize = this->VertexMapAllocatedSize; this->VertexMapAllocatedSize <<= 1; this->VertexMap = (vtkIdType *) realloc(this->VertexMap, sizeof(vtkIdType)*this->VertexMapAllocatedSize); for(int i = oldSize; i < this->VertexMapAllocatedSize - 1; i++) this->VertexMap[i] = 0; } // same thing with the triangle map if(!this->TriangleVertexMapAllocatedSize) { // first allocate an arbitrary size this->TriangleVertexMapAllocatedSize = vtkReebGraphInitialStreamSize; this->TriangleVertexMap = (int *) malloc( sizeof(int)*this->TriangleVertexMapAllocatedSize); memset(this->TriangleVertexMap, 0, sizeof(int)*this->TriangleVertexMapAllocatedSize); } else if(this->TriangleVertexMapSize >= this->TriangleVertexMapAllocatedSize - 3) { int oldSize = this->TriangleVertexMapAllocatedSize; this->TriangleVertexMapAllocatedSize <<= 1; this->TriangleVertexMap = (int *) realloc(this->TriangleVertexMap, sizeof(int)*this->TriangleVertexMapAllocatedSize); for(int i = oldSize; i < this->TriangleVertexMapAllocatedSize - 1; i++) this->TriangleVertexMap[i] = 0; } // Add the vertices to the stream std::map::iterator sIter; // vertex0 sIter = this->VertexStream.find(vertex0Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex0Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex0Id, scalar0); this->VertexMapSize++; this->TriangleVertexMapSize++; } // vertex1 sIter = this->VertexStream.find(vertex1Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex1Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex1Id, scalar1); this->VertexMapSize++; this->TriangleVertexMapSize++; } // vertex2 sIter = this->VertexStream.find(vertex2Id); if(sIter == this->VertexStream.end()) { // this vertex hasn't been streamed yet, let's add it this->VertexStream[vertex2Id] = this->VertexMapSize; this->VertexMap[this->VertexMapSize] = this->AddMeshVertex(vertex2Id, scalar2); this->VertexMapSize++; this->TriangleVertexMapSize++; } this->AddMeshTriangle(vertex0Id, scalar0, vertex1Id, scalar1, vertex2Id, scalar2); return 0; } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkPolyData *mesh, vtkDataArray *scalarField) { for(vtkIdType i = 0; i < mesh->GetNumberOfCells(); i++) { vtkCell *triangle = mesh->GetCell(i); vtkIdList *trianglePointList = triangle->GetPointIds(); if(trianglePointList->GetNumberOfIds() != 3) return vtkReebGraph::ERR_NOT_A_SIMPLICIAL_MESH; StreamTriangle(trianglePointList->GetId(0), scalarField->GetComponent(trianglePointList->GetId(0),0), trianglePointList->GetId(1), scalarField->GetComponent(trianglePointList->GetId(1),0), trianglePointList->GetId(2), scalarField->GetComponent(trianglePointList->GetId(2),0)); } this->Storage->inputMesh = mesh; this->Storage->inputScalarField = scalarField; this->CloseStream(); return 0; } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkUnstructuredGrid *mesh, vtkDataArray *scalarField) { for(vtkIdType i = 0; i < mesh->GetNumberOfCells(); i++) { vtkCell *tet = mesh->GetCell(i); vtkIdList *tetPointList = tet->GetPointIds(); if(tetPointList->GetNumberOfIds() != 4) return vtkReebGraph::ERR_NOT_A_SIMPLICIAL_MESH; StreamTetrahedron(tetPointList->GetId(0), scalarField->GetComponent(tetPointList->GetId(0),0), tetPointList->GetId(1), scalarField->GetComponent(tetPointList->GetId(1),0), tetPointList->GetId(2), scalarField->GetComponent(tetPointList->GetId(2),0), tetPointList->GetId(3), scalarField->GetComponent(tetPointList->GetId(3),0)); } this->Storage->inputMesh = mesh; this->Storage->inputScalarField = scalarField; this->CloseStream(); return 0; } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::GetNumberOfArcs() { if(!this->ArcNumber) for(vtkIdType arcId = 1; arcId < this->MainArcTable.Size; arcId++) { // check if arc is cleared if(!(this->GetArc(arcId)->LabelId1 == ((int)-2))) this->ArcNumber++; } return this->ArcNumber; } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::GetNumberOfConnectedComponents() { if(!this->ArcLoopTable) this->FindLoops(); return this->ConnectedComponentNumber; } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::GetNumberOfNodes() { if(!this->NodeNumber) for(vtkIdType nodeId = 1; nodeId < this->MainNodeTable.Size; nodeId++) { // check if node is cleared if(!(this->GetNode(nodeId)->ArcUpId == ((int)-2))) this->NodeNumber++; } return this->NodeNumber; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetNextNodeId() { for(vtkIdType nodeId = this->currentNodeId + 1; nodeId < this->MainNodeTable.Size; nodeId++) { // check if node is cleared if(!(this->GetNode(nodeId)->ArcUpId == ((int)-2))) { this->currentNodeId = nodeId; return this->currentNodeId; } } return this->currentNodeId; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetPreviousNodeId() { if(!this->currentNodeId) { return this->GetNextNodeId(); } for(vtkIdType nodeId = this->currentNodeId - 1; nodeId > 0; nodeId--) { // check if node is cleared if(!(this->GetNode(nodeId)->ArcUpId == ((int)-2))) { this->currentNodeId = nodeId; return this->currentNodeId; } } return this->currentNodeId; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetNextArcId() { for(vtkIdType arcId = this->currentArcId + 1; arcId < this->MainArcTable.Size; arcId++) { // check if arc is cleared if(!(this->GetArc(arcId)->LabelId1 == ((int)-2))) { this->currentArcId = arcId; return this->currentArcId; } } return this->currentArcId; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetPreviousArcId() { if(!this->currentArcId) { return this->GetNextArcId(); } for(vtkIdType arcId = this->currentArcId - 1; arcId > 0; arcId--) { // check if arc is cleared if(!(this->GetArc(arcId)->LabelId1 == ((int)-2))) { this->currentArcId = arcId; return this->currentArcId; } } return this->currentArcId; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetArcDownNodeId(vtkIdType arcId) { return (this->GetArc(arcId))->NodeId0; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetArcUpNodeId(vtkIdType arcId) { return (this->GetArc(arcId))->NodeId1; } //---------------------------------------------------------------------------- double vtkReebGraph::Implementation::GetNodeScalarValue(vtkIdType nodeId) { return (this->GetNode(nodeId))->Value; } //---------------------------------------------------------------------------- vtkIdType vtkReebGraph::Implementation::GetNodeVertexId(vtkIdType nodeId) { return (this->GetNode(nodeId))->VertexId; } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkPolyData *mesh, vtkIdType scalarFieldId) { vtkPointData *pointData = mesh->GetPointData(); vtkDataArray *scalarField = pointData->GetArray(scalarFieldId); if(!scalarField) return vtkReebGraph::ERR_NO_SUCH_FIELD; return this->Build(mesh, scalarField); } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkUnstructuredGrid *mesh, vtkIdType scalarFieldId) { vtkPointData *pointData = mesh->GetPointData(); vtkDataArray *scalarField = pointData->GetArray(scalarFieldId); if(!scalarField) return vtkReebGraph::ERR_NO_SUCH_FIELD; return this->Build(mesh, scalarField); } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkPolyData *mesh, const char* scalarFieldName) { int scalarFieldId = 0; vtkPointData *pointData = mesh->GetPointData(); vtkDataArray *scalarField = pointData->GetArray(scalarFieldName, scalarFieldId); if(!scalarField) return vtkReebGraph::ERR_NO_SUCH_FIELD; return this->Build(mesh, scalarField); } //---------------------------------------------------------------------------- int vtkReebGraph::Build(vtkUnstructuredGrid *mesh, const char* scalarFieldName) { int scalarFieldId = 0; vtkPointData *pointData = mesh->GetPointData(); vtkDataArray *scalarField = pointData->GetArray(scalarFieldName, scalarFieldId); if(!scalarField) return vtkReebGraph::ERR_NO_SUCH_FIELD; return this->Build(mesh, scalarField); } //---------------------------------------------------------------------------- int vtkReebGraph::Implementation::GetNumberOfLoops() { if(!this->ArcLoopTable) this->FindLoops(); return this->LoopNumber - this->RemovedLoopNumber; } //---------------------------------------------------------------------------- inline vtkIdType vtkReebGraph::Implementation::AddArc(vtkIdType nodeId0, vtkIdType nodeId1) { if (!vtkReebGraphIsSmaller(this, nodeId0, nodeId1, this->GetNode(nodeId0), this->GetNode(nodeId1))) vtkReebGraphSwapVars(vtkIdType, nodeId0, nodeId1); vtkIdType nodevtkReebArcble[] = { nodeId0, nodeId1}; return AddPath(2, nodevtkReebArcble, 0); }