OpenCOVER
Tipsify.h
Go to the documentation of this file.
1/* This file is part of COVISE.
2
3 You can use it under the terms of the GNU Lesser General Public License
4 version 2.1 or later, see lgpl-2.1.txt.
5
6 * License: LGPL 2+ */
7
8#ifndef COVER_TIPSIFY_H
9#define COVER_TIPSIFY_H
10
19#include <cassert>
20#include <vector>
21#include <algorithm>
22
23namespace opencover
24{
25
26namespace Tipsify {
27
28template<class Index>
29struct Neighbors {
30 Index maxIndexP1 = 0; // maximum index plus 1
31 std::vector<int> use; // no. of triangles where vertex is used
32 std::vector<Index> tl; // list of triangles
33 std::vector<Index> offset; // offset into list of triangles where sublist for a vertex starts
34};
35
36// build neighbors
37template<class Index>
38Neighbors<Index> buildNeighbours(const Index *idx, size_t size, Index maxIndex) {
39
41
42 N.use.resize(maxIndex+1);
43 const Index *end = idx+size;
44 for (const Index *v = idx; v<end; ++v) {
45 if (*v + 1 > N.maxIndexP1) {
46 N.maxIndexP1 = *v + 1;
47 if (N.use.size()<N.maxIndexP1)
48 N.use.resize(N.maxIndexP1);
49 }
50 ++N.use[*v];
51 }
52 N.use.resize(N.maxIndexP1);
53
54 N.offset.reserve(N.maxIndexP1 + 1);
55 Index sum = 0;
56 N.offset.push_back(sum);
57 N.offset.push_back(sum);
58 for (Index v=0; v<N.maxIndexP1; ++v) {
59 sum += N.use[v];
60 N.offset.push_back(sum);
61 }
62 assert(sum == size);
63 assert(N.offset[0] == 0);
64 assert(N.offset[1] == 0);
65 assert(N.maxIndexP1 == 0 || N.offset[N.maxIndexP1] < sum);
66
67 N.tl.resize(sum);
68 for (size_t i=0; i<size; ++i) {
69 Index v = idx[i];
70 N.tl[N.offset[v+1]++] = i/3;
71 }
72 assert(N.offset[N.maxIndexP1] == sum);
73
74 return N;
75}
76
77} // namespace Tipsify
78
79template<class Index>
80void tipsify(Index *idx, size_t num, int cachesize=20, int batchsize=-1) {
81
82 enum IndexValues : Index {
83 InvalidIndex = ~Index(0)
84 };
85
86 using namespace Tipsify;
87
88 if (num == 0)
89 return;
90
91 auto N = buildNeighbours<Index>(idx, num, num);
92
93 std::vector<Index> out; // optimized index list
94 out.reserve(num);
95
96 std::vector<char> emitted(N.tl.size()); // if a triangle has already been emitted
97
98 std::vector<Index> deadEndStack;
99 std::vector<int> cachetime(N.maxIndexP1);
100 int time=cachesize+1;
101 size_t cursor = 0;
102 Index f = num > 0 ? idx[0] : InvalidIndex; // start vertex for triangle fans
103 int remaininbatch = batchsize;
104 while (f != InvalidIndex) {
105
106 std::set<Index> candidates;
107 for (Index i=N.offset[f]; i<N.offset[f+1]; ++i) {
108 Index t = N.tl[i];
109 if (!emitted[t]) {
110 emitted[t] = true;
111 for (int i=0; i<3; ++i) {
112 --remaininbatch;
113 Index v = idx[t*3+i];
114 out.push_back(v);
115 deadEndStack.push_back(v);
116 candidates.insert(v);
117 --N.use[v];
118 if (time-cachetime[v] > cachesize) {
119 // not in cache
120 cachetime[v] = time;
121 ++time;
122 }
123 }
124 }
125 }
126
127 f = InvalidIndex;
128 bool startFresh = false;
129 if (batchsize>0) {
130 startFresh = remaininbatch==0;
131
132 while (remaininbatch <= 0)
133 remaininbatch += batchsize;
134
135 if (startFresh) {
136 time += batchsize;
137 deadEndStack.clear();
138 }
139 }
140
141 // find another vertex to fan triangles around
142 if (!startFresh) {
143 int maxPriority = -1;
144 for (auto v: candidates) {
145 // try candidates from previous fan
146 if (N.use[v] == 0)
147 continue;
148 int priority = 0;
149 if (time - cachetime[v] + 2*N.use[v] <= cachesize && (batchsize<0 || N.use[v]<=remaininbatch))
150 priority = time-cachetime[v];
151 if (priority > maxPriority) {
152 maxPriority = priority;
153 f = v;
154 }
155 }
156 if (f == InvalidIndex) {
157 // try candidates from dead-end stack
158 while (!deadEndStack.empty()) {
159 Index v = deadEndStack.back();
160 deadEndStack.pop_back();
161 if (N.use[v] > 0) {
162 f = v;
163 break;
164 }
165 }
166 }
167 }
168 if (f == InvalidIndex) {
169 // take another vertex from input
170 for (; cursor < num; ++cursor) {
171 Index v = idx[cursor];
172 if (N.use[v] > 0) {
173 f = v;
174 break;
175 }
176 }
177 }
178 }
179
180 assert(out.size() == num);
181 std::copy(out.begin(), out.end(), idx);
182}
183
184}
185#endif
Definition: ARToolKit.h:33
void tipsify(Index *idx, size_t num, int cachesize=20, int batchsize=-1)
Definition: Tipsify.h:80
Neighbors< Index > buildNeighbours(const Index *idx, size_t size, Index maxIndex)
Definition: Tipsify.h:38
Definition: Tipsify.h:29
std::vector< Index > offset
Definition: Tipsify.h:33
std::vector< int > use
Definition: Tipsify.h:31
std::vector< Index > tl
Definition: Tipsify.h:32
Index maxIndexP1
Definition: Tipsify.h:30