TTK
Loading...
Searching...
No Matches
TwoSkeleton.cpp
Go to the documentation of this file.
1#include <TwoSkeleton.h>
2#include <boost/container/small_vector.hpp>
3
4using namespace ttk;
5
7 setDebugMsgPrefix("TwoSkeleton");
8}
9
11 const CellArray &cellArray,
12 FlatJaggedArray &cellNeighbors,
13 const FlatJaggedArray &edgeStars) const {
14
15 Timer t;
16
17 printMsg("Building cell neighbors", 0, 0, 1, debug::LineMode::REPLACE);
18
19 const SimplexId cellNumber = cellArray.getNbCells();
20 const SimplexId edgeNumber = edgeStars.size();
21 std::vector<SimplexId> offsets(cellNumber + 1);
22 // number of neigbhors processed per cell
23 std::vector<SimplexId> neighborsId(cellNumber);
24
25 for(SimplexId i = 0; i < edgeNumber; i++) {
26 if(edgeStars.size(i) == 2) {
27 // tetra cells in edge i's star
28 const auto cs0 = edgeStars.get(i, 0);
29 const auto cs1 = edgeStars.get(i, 1);
30 offsets[cs0 + 1]++;
31 offsets[cs1 + 1]++;
32 }
33 }
34
35 // compute partial sum of number of neighbors per vertex
36 for(size_t i = 1; i < offsets.size(); ++i) {
37 offsets[i] += offsets[i - 1];
38 }
39
40 // allocate flat neighbors vector
41 std::vector<SimplexId> neighbors(offsets.back());
42
43 // fill flat neighbors vector using offsets and neighbors count vectors
44 for(SimplexId i = 0; i < edgeNumber; i++) {
45 if(edgeStars.size(i) == 2) {
46 // tetra cells in edge i's star
47 const auto cs0 = edgeStars.get(i, 0);
48 const auto cs1 = edgeStars.get(i, 1);
49 neighbors[offsets[cs0] + neighborsId[cs0]] = cs1;
50 neighborsId[cs0]++;
51 neighbors[offsets[cs1] + neighborsId[cs1]] = cs0;
52 neighborsId[cs1]++;
53 }
54 }
55
56 // fill FlatJaggedArray struct
57 cellNeighbors.setData(std::move(neighbors), std::move(offsets));
58
59 printMsg("Built " + std::to_string(cellNumber) + " cell neighbors", 1,
60 t.getElapsedTime(), 1);
61
62 return 0;
63}
64
66 const SimplexId &vertexNumber,
67 const CellArray &cellArray,
68 FlatJaggedArray &cellNeighbors,
69 FlatJaggedArray *vertexStars) const {
70
71 auto localVertexStars = vertexStars;
72 FlatJaggedArray defaultVertexStars{};
73
74 if(!localVertexStars) {
75 localVertexStars = &defaultVertexStars;
76 }
77
78 if(localVertexStars->empty()) {
79 ZeroSkeleton zeroSkeleton;
80 zeroSkeleton.setThreadNumber(threadNumber_);
81 zeroSkeleton.setDebugLevel(debugLevel_);
82 zeroSkeleton.buildVertexStars(vertexNumber, cellArray, *localVertexStars);
83 }
84
85 Timer t;
86
88 "Building cell neighbors", 0, 0, threadNumber_, debug::LineMode::REPLACE);
89
90 const SimplexId cellNumber = cellArray.getNbCells();
91 using boost::container::small_vector;
92 // for each cell/triangle, a vector of neighbors
93 std::vector<small_vector<SimplexId, 3>> neighbors(cellNumber);
94
95#ifdef TTK_ENABLE_OPENMP
96#pragma omp parallel for num_threads(threadNumber_)
97#endif
98 for(SimplexId cid = 0; cid < cellNumber; cid++) {
99 const SimplexId nbVertCell = cellArray.getCellVertexNumber(cid);
100
101 for(SimplexId j = 0; j < nbVertCell; j++) {
102
103 SimplexId v0 = cellArray.getCellVertex(cid, j);
104 SimplexId v1 = cellArray.getCellVertex(cid, (j + 1) % nbVertCell);
105
106 // perform an intersection of the 2 sorted star lists
107 SimplexId pos0 = 0, pos1 = 0;
108 SimplexId intersection = -1;
109
110 while(pos0 < localVertexStars->size(v0)
111 && pos1 < localVertexStars->size(v1)) {
112
113 SimplexId biggest = localVertexStars->get(v0, pos0);
114 if(localVertexStars->get(v1, pos1) > biggest) {
115 biggest = localVertexStars->get(v1, pos1);
116 }
117
118 for(SimplexId l = pos0; l < localVertexStars->size(v0); l++) {
119 if(localVertexStars->get(v0, l) < biggest) {
120 pos0++;
121 } else {
122 break;
123 }
124 }
125 for(SimplexId l = pos1; l < localVertexStars->size(v1); l++) {
126 if(localVertexStars->get(v1, l) < biggest) {
127 pos1++;
128 } else {
129 break;
130 }
131 }
132
133 if(localVertexStars->get(v0, pos0) == localVertexStars->get(v1, pos1)) {
134 if(localVertexStars->get(v0, pos0) != cid) {
135 intersection = localVertexStars->get(v0, pos0);
136 break;
137 }
138
139 pos0++;
140 pos1++;
141 }
142 }
143
144 if(intersection != -1) {
145 neighbors[cid].emplace_back(intersection);
146 }
147 }
148 }
149
150 // convert to a FlatJaggedArray
151 cellNeighbors.fillFrom(neighbors);
152
153 printMsg("Built " + std::to_string(cellNumber) + " cell neighbors", 1,
155
156 return 0;
157}
158
160 const SimplexId &vertexNumber,
161 const CellArray &cellArray,
162 FlatJaggedArray &edgeTriangleList,
163 const std::vector<std::array<SimplexId, 2>> &edgeList,
164 std::vector<std::array<SimplexId, 3>> *triangleEdgeList) const {
165
166 // check the consistency of the variables -- to adapt
167#ifndef TTK_ENABLE_KAMIKAZE
168 if(vertexNumber <= 0)
169 return -1;
170#endif
171
172 auto localTriangleEdgeList = triangleEdgeList;
173 std::vector<std::array<SimplexId, 3>> defaultTriangleEdgeList{};
174 if(!localTriangleEdgeList) {
175 localTriangleEdgeList = &defaultTriangleEdgeList;
176 }
177
178 if(localTriangleEdgeList->empty()) {
180 vertexNumber, cellArray, *localTriangleEdgeList, edgeList);
181 }
182
183 const auto edgeNumber{edgeList.size()};
184
185 std::vector<SimplexId> offsets(edgeNumber + 1);
186 // number of neighbors processed per vertex
187 std::vector<SimplexId> trianglesId(edgeNumber);
188
189 Timer t;
190
191 printMsg("Building edge triangles", 0, 0, threadNumber_,
193
194 // store number of triangles per edge
195 for(const auto &te : *localTriangleEdgeList) {
196 offsets[te[0] + 1]++;
197 offsets[te[1] + 1]++;
198 offsets[te[2] + 1]++;
199 }
200
201 // compute partial sum of number of triangles per edge
202 for(size_t i = 1; i < offsets.size(); ++i) {
203 offsets[i] += offsets[i - 1];
204 }
205
206 // allocate flat edge triangle vector
207 std::vector<SimplexId> edgeTriangles(offsets.back());
208
209 // fill flat neighbors vector using offsets and neighbors count vectors
210 for(size_t i = 0; i < localTriangleEdgeList->size(); ++i) {
211 const auto &te{(*localTriangleEdgeList)[i]};
212 edgeTriangles[offsets[te[0]] + trianglesId[te[0]]] = i;
213 trianglesId[te[0]]++;
214 edgeTriangles[offsets[te[1]] + trianglesId[te[1]]] = i;
215 trianglesId[te[1]]++;
216 edgeTriangles[offsets[te[2]] + trianglesId[te[2]]] = i;
217 trianglesId[te[2]]++;
218 }
219
220 // fill FlatJaggedArray struct
221 edgeTriangleList.setData(std::move(edgeTriangles), std::move(offsets));
222
223 printMsg("Built " + std::to_string(edgeNumber) + " edge triangles", 1,
225
226 return 0;
227}
228
230 const SimplexId &vertexNumber,
231 const CellArray &cellArray,
232 std::vector<std::array<SimplexId, 3>> *triangleList,
233 FlatJaggedArray *triangleStars,
234 std::vector<std::array<SimplexId, 4>> *cellTriangleList) const {
235
236 Timer t;
237
238 // check the consistency of the variables -- to adapt
239#ifndef TTK_ENABLE_KAMIKAZE
240 if(vertexNumber <= 0)
241 return -1;
242 if((!triangleList) && (!triangleStars) && (!cellTriangleList)) {
243 // we've got nothing to do here.
244 return -2;
245 }
246#endif
247
248 // check parameters consistency (this method is useless in 2D)
249 const auto dim = cellArray.getCellVertexNumber(0) - 1;
250 if(dim < 3) {
251 this->printWrn("Calling buildTriangleList is useless in "
252 + std::to_string(dim) + "D, skipping...");
253 return -1;
254 }
255
256 printMsg(
257 "Building triangles", 0, 0, threadNumber_, ttk::debug::LineMode::REPLACE);
258
259 const SimplexId cellNumber = cellArray.getNbCells();
260
261 // we need cellTriangleList to compute triangleStars
262 std::vector<std::array<SimplexId, 4>> defaultCellTriangleList{};
263 if(triangleStars != nullptr && cellTriangleList == nullptr) {
264 cellTriangleList = &defaultCellTriangleList;
265 }
266
267 if(cellTriangleList) {
268 cellTriangleList->resize(cellNumber, {-1, -1, -1, -1});
269 }
270
271 struct TriangleData {
272 // the two higher vertices id of the triangle
273 std::array<SimplexId, 2> highVerts{};
274 // the triangle id
275 SimplexId id{-1};
276 TriangleData(std::array<SimplexId, 2> hVerts, SimplexId i)
277 : highVerts{hVerts}, id{i} {
278 }
279 };
280
281 using boost::container::small_vector;
282 // for each vertex, a vector of TriangleData
283 std::vector<small_vector<TriangleData, 8>> triangleTable(vertexNumber);
284
285 SimplexId nTriangles{};
286
287 printMsg("Building triangles", 0.25, t.getElapsedTime(), 1,
289
290 for(SimplexId cid = 0; cid < cellNumber; cid++) {
291 // a tetra cell has 4 faces
292 for(size_t j = 0; j < 4; j++) {
293 std::array<SimplexId, 3> triangle{};
294 for(size_t k = 0; k < 3; k++) {
295 // TODO: ASSUME Regular Mesh Here!
296 triangle[k] = cellArray.getCellVertex(cid, (j + k) % 4);
297 }
298 std::sort(triangle.begin(), triangle.end());
299 auto &ttable = triangleTable[triangle[0]];
300
301 // check if current triangle already registered in triangleTable
302 // via another tetra in its star
303 bool found{false};
304 for(auto &d : ttable) {
305 if(d.highVerts[0] == triangle[1] && d.highVerts[1] == triangle[2]) {
306 found = true;
307 if(cellTriangleList != nullptr) {
308 (*cellTriangleList)[cid][j] = d.id;
309 }
310 break;
311 }
312 }
313 if(!found) {
314 // new triangle added
315 ttable.emplace_back(
316 TriangleData{{triangle[1], triangle[2]}, nTriangles});
317 if(cellTriangleList != nullptr) {
318 (*cellTriangleList)[cid][j] = nTriangles;
319 }
320 nTriangles++;
321 }
322 }
323 }
324
325 printMsg(
326 "Building triangles", 0.5, t.getElapsedTime(), 1, debug::LineMode::REPLACE);
327
328 // resize vectors to the correct size
329 if(triangleList) {
330 triangleList->resize(nTriangles);
331 }
332
333 // fill data buffers in parallel
334
335#ifdef TTK_ENABLE_OPENMP
336#pragma omp parallel for num_threads(this->threadNumber_)
337#endif // TTK_ENABLE_OPENMP
338 for(SimplexId i = 0; i < vertexNumber; ++i) {
339 const auto &ttable = triangleTable[i];
340 for(const auto &data : ttable) {
341 if(triangleList != nullptr) {
342 (*triangleList)[data.id] = {i, data.highVerts[0], data.highVerts[1]};
343 }
344 }
345 }
346
347 printMsg("Building triangles", 0.75, t.getElapsedTime(), 1,
349
350 if(cellTriangleList != nullptr && triangleStars != nullptr) {
351 std::vector<SimplexId> offsets(nTriangles + 1);
352 // number of cells processed per vertex
353 std::vector<SimplexId> starIds(nTriangles);
354
355 // store number of cells per triangle
356 for(const auto &c : *cellTriangleList) {
357 offsets[c[0] + 1]++;
358 offsets[c[1] + 1]++;
359 offsets[c[2] + 1]++;
360 offsets[c[3] + 1]++;
361 }
362
363 // compute partial sum of number of cells per triangle
364 for(size_t i = 1; i < offsets.size(); ++i) {
365 offsets[i] += offsets[i - 1];
366 }
367
368 // allocate flat triangle stars vector
369 std::vector<SimplexId> triangleSt(offsets.back());
370
371 // fill flat neighbors vector using offsets and neighbors count vectors
372 for(size_t i = 0; i < cellTriangleList->size(); ++i) {
373 const auto &ct{(*cellTriangleList)[i]};
374 triangleSt[offsets[ct[0]] + starIds[ct[0]]] = i;
375 starIds[ct[0]]++;
376 triangleSt[offsets[ct[1]] + starIds[ct[1]]] = i;
377 starIds[ct[1]]++;
378 triangleSt[offsets[ct[2]] + starIds[ct[2]]] = i;
379 starIds[ct[2]]++;
380 triangleSt[offsets[ct[3]] + starIds[ct[3]]] = i;
381 starIds[ct[3]]++;
382 }
383
384 // fill FlatJaggedArray struct
385 triangleStars->setData(std::move(triangleSt), std::move(offsets));
386 }
387
388 printMsg("Built " + std::to_string(nTriangles) + " triangles", 1,
389 t.getElapsedTime(), 1);
390 // ethaneDiolMedium.vtu, 70Mtets, hal9000 (12coresHT)// 1 thread: 58.5631 s//
391 // 24 threads: 87.5816 s (~) ethaneDiol.vtu, 8.7Mtets, vger (2coresHT) - no
392 // tet adj// 1 thread: 5.7427 s// 4 threads: 9.14764 s (~)
393 // ethaneDiol.vtu, 8.7Mtets, vger (2coresHT) - tet adjacency// 1
394 // thread: 8.59854 s// 4 threads: 15.837 s
395 // (~) ethaneDiol.vtu, 8.7Mtets, vger (2coresHT) - tet adjacency only// 1
396 // thread: 6.85897 s// 4 threads: 14.78 s (~)
397 return 0;
398}
399
401 const SimplexId &vertexNumber,
402 const CellArray &cellArray,
403 std::vector<std::array<SimplexId, 3>> &triangleEdgeList,
404 const std::vector<std::array<SimplexId, 2>> &edgeList,
405 FlatJaggedArray *vertexEdgeList,
406 std::vector<std::array<SimplexId, 3>> *triangleList,
407 FlatJaggedArray *triangleStarList,
408 std::vector<std::array<SimplexId, 4>> *cellTriangleList) const {
409
410 auto localVertexEdgeList = vertexEdgeList;
411 FlatJaggedArray defaultVertexEdgeList{};
412 if(!localVertexEdgeList) {
413 localVertexEdgeList = &defaultVertexEdgeList;
414 }
415
416 if(localVertexEdgeList->empty()) {
417
418 ZeroSkeleton zeroSkeleton;
419 zeroSkeleton.setDebugLevel(debugLevel_);
420 zeroSkeleton.setThreadNumber(threadNumber_);
421
422 zeroSkeleton.buildVertexEdges(
423 vertexNumber, edgeList, (*localVertexEdgeList));
424 }
425
426 // NOTE:
427 // triangleStarList and cellTriangleList: we do not need these guys but we
428 // can compute them for free optionally.
429
430 auto localTriangleList = triangleList;
431 std::vector<std::array<SimplexId, 3>> defaultTriangleList{};
432 if(!localTriangleList) {
433 localTriangleList = &defaultTriangleList;
434 }
435 if(!localTriangleList->size()) {
436
437 buildTriangleList(vertexNumber, cellArray, localTriangleList,
438 triangleStarList, cellTriangleList);
439 }
440
441 triangleEdgeList.resize(localTriangleList->size());
442
443 Timer tm;
444
445 printMsg("Building triangle edges", 0, 0, threadNumber_,
447
448 // now for each triangle, grab its vertices, add the edges in the triangle
449 // with no duplicate
450 // let's do the real stuff
451#ifdef TTK_ENABLE_OPENMP
452#pragma omp parallel for num_threads(threadNumber_)
453#endif // TTK_ENABLE_OPENMP
454 for(size_t i = 0; i < localTriangleList->size(); i++) {
455 const auto &t = (*localTriangleList)[i];
456 const auto beg0 = localVertexEdgeList->get_ptr(t[0], 0);
457 const auto end0 = beg0 + localVertexEdgeList->size(t[0]);
458 const auto beg1 = localVertexEdgeList->get_ptr(t[1], 0);
459 const auto end1 = beg1 + localVertexEdgeList->size(t[1]);
460 const auto beg2 = localVertexEdgeList->get_ptr(t[2], 0);
461 const auto end2 = beg2 + localVertexEdgeList->size(t[2]);
462 std::set_intersection(beg0, end0, beg1, end1, &triangleEdgeList[i][0]);
463 std::set_intersection(beg0, end0, beg2, end2, &triangleEdgeList[i][1]);
464 std::set_intersection(beg1, end1, beg2, end2, &triangleEdgeList[i][2]);
465 std::sort(triangleEdgeList[i].begin(), triangleEdgeList[i].end());
466 }
467
468 SimplexId triangleNumber = localTriangleList->size();
469
470 printMsg("Built " + std::to_string(triangleNumber) + " triangle edges", 1,
472
473 return 0;
474}
475
477 const std::vector<std::array<SimplexId, 3>> &triangleList,
478 const FlatJaggedArray &triangleStars,
479 const CellArray &cellArray,
480 FlatJaggedArray &triangleLinks) const {
481
482#ifndef TTK_ENABLE_KAMIKAZE
483 if(triangleList.empty())
484 return -1;
485 if((triangleStars.empty()) || (triangleStars.size() != triangleList.size()))
486 return -2;
487#endif
488
489 Timer tm;
490
491 // check parameters consistency (this method is useless in 2D)
492 const auto dim = cellArray.getCellVertexNumber(0) - 1;
493 if(dim == 2) {
494 this->printWrn("Calling buildTriangleLinks is useless in 2D, skipping...");
495 return -1;
496 }
497
498 const SimplexId triangleNumber = triangleList.size();
499 std::vector<SimplexId> offsets(triangleNumber + 1);
500 // one vertex per star
501 std::vector<SimplexId> links(triangleStars.dataSize());
502
503 printMsg("Building triangle links", 0, 0, threadNumber_,
505
506#ifdef TTK_ENABLE_OPENMP
507#pragma omp parallel for num_threads(threadNumber_)
508#endif // TTK_ENABLE_OPENMP
509 for(SimplexId i = 0; i < triangleNumber; i++) {
510
511 // copy the triangleStars offsets array
512 offsets[i] = triangleStars.offset(i);
513
514 const auto &t = triangleList[i];
515 for(SimplexId j = 0; j < triangleStars.size(i); j++) {
516 // for each tetra in triangle i's star, get the opposite vertex
517 for(size_t k = 0; k < 4; k++) {
518 const auto v = cellArray.getCellVertex(triangleStars.get(i, j), k);
519 if(v != t[0] && v != t[1] && v != t[2]) {
520 links[offsets[i] + j] = v;
521 break;
522 }
523 }
524 }
525 }
526
527 // don't forget the last offset
528 offsets[triangleNumber] = triangleStars.offset(triangleNumber);
529
530 triangleLinks.setData(std::move(links), std::move(offsets));
531
532 printMsg("Built " + std::to_string(triangleNumber) + " triangle links", 1,
534
535 return 0;
536}
537
539 const SimplexId &vertexNumber,
540 const std::vector<std::array<SimplexId, 3>> &triangleList,
541 FlatJaggedArray &vertexTriangles) const {
542
543 Timer tm;
544
545 printMsg("Building vertex triangles", 0, 0, 1, ttk::debug::LineMode::REPLACE);
546
547 std::vector<SimplexId> offsets(vertexNumber + 1);
548 // number of triangles processed per vertex
549 std::vector<SimplexId> trianglesId(vertexNumber);
550
551 // store number of triangles per vertex
552 for(const auto &t : triangleList) {
553 offsets[t[0] + 1]++;
554 offsets[t[1] + 1]++;
555 offsets[t[2] + 1]++;
556 }
557
558 // compute partial sum of number of neighbors per vertex
559 for(size_t i = 1; i < offsets.size(); ++i) {
560 offsets[i] += offsets[i - 1];
561 }
562
563 // allocate flat neighbors vector
564 std::vector<SimplexId> data(offsets.back());
565
566 // fill flat data vector using offsets and triangles count vectors
567 for(size_t i = 0; i < triangleList.size(); ++i) {
568 const auto &t{triangleList[i]};
569 data[offsets[t[0]] + trianglesId[t[0]]] = i;
570 trianglesId[t[0]]++;
571 data[offsets[t[1]] + trianglesId[t[1]]] = i;
572 trianglesId[t[1]]++;
573 data[offsets[t[2]] + trianglesId[t[2]]] = i;
574 trianglesId[t[2]]++;
575 }
576
577 // fill FlatJaggedArray struct
578 vertexTriangles.setData(std::move(data), std::move(offsets));
579
580 printMsg("Built " + std::to_string(vertexNumber) + " vertex triangles", 1,
581 tm.getElapsedTime(), 1);
582
583 return 0;
584}
int threadNumber_
Definition: BaseClass.h:95
virtual int setThreadNumber(const int threadNumber)
Definition: BaseClass.h:80
CellArray generic array of cells
LongSimplexId getCellVertex(const LongSimplexId cellId, const SimplexId localVertId) const
LongSimplexId getNbCells() const
Get the number of cells in the array.
SimplexId getCellVertexNumber(const LongSimplexId cellId) const
int debugLevel_
Definition: Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:159
void setDebugMsgPrefix(const std::string &prefix)
Definition: Debug.h:364
virtual int setDebugLevel(const int &debugLevel)
Definition: Debug.cpp:147
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
Replacement for std::vector<std::vector<SimplexId>>
size_t dataSize() const
Returns the size of the data_ member.
SimplexId get(SimplexId id, SimplexId local) const
Returns the data inside the sub-vectors.
void setData(std::vector< SimplexId > &&data, std::vector< SimplexId > &&offsets)
Set internal data from pre-existing vectors.
void fillFrom(const std::vector< T > &src, int threadNumber=1)
Fill buffers from a std::vector<std::vector<SimplexId>>
SimplexId size(SimplexId id) const
Get the size of a particular sub-vector.
SimplexId offset(SimplexId id) const
Get the offset of a particular sub-vector.
bool empty() const
If the underlying buffers are empty.
double getElapsedTime()
Definition: Timer.h:15
int buildTriangleEdgeList(const SimplexId &vertexNumber, const CellArray &cellArray, std::vector< std::array< SimplexId, 3 > > &triangleEdgeList, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray *vertexEdgeList=nullptr, std::vector< std::array< SimplexId, 3 > > *triangleList=nullptr, FlatJaggedArray *triangleStarList=nullptr, std::vector< std::array< SimplexId, 4 > > *cellTriangleList=nullptr) const
int buildVertexTriangles(const SimplexId &vertexNumber, const std::vector< std::array< SimplexId, 3 > > &triangleList, FlatJaggedArray &vertexTriangles) const
int buildCellNeighborsFromEdges(const CellArray &cellArray, FlatJaggedArray &cellNeighbors, const FlatJaggedArray &edgeStars) const
Definition: TwoSkeleton.cpp:10
int buildTriangleLinks(const std::vector< std::array< SimplexId, 3 > > &triangleList, const FlatJaggedArray &triangleStars, const CellArray &cellArray, FlatJaggedArray &triangleLinks) const
int buildTriangleList(const SimplexId &vertexNumber, const CellArray &cellArray, std::vector< std::array< SimplexId, 3 > > *triangleList=nullptr, FlatJaggedArray *triangleStars=nullptr, std::vector< std::array< SimplexId, 4 > > *cellTriangleList=nullptr) const
int buildEdgeTriangles(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &edgeTriangleList, const std::vector< std::array< SimplexId, 2 > > &edgeList, std::vector< std::array< SimplexId, 3 > > *triangleEdgeList=nullptr) const
int buildCellNeighborsFromVertices(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &cellNeighbors, FlatJaggedArray *vertexStars=nullptr) const
Definition: TwoSkeleton.cpp:65
ZeroSkeleton processing package.
Definition: ZeroSkeleton.h:25
int buildVertexEdges(const SimplexId &vertexNumber, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray &vertexEdges) const
Definition: ZeroSkeleton.cpp:9
int buildVertexStars(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &vertexStars) const
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22