Blender  V2.93
GeomCleaner.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
22 #if 0
23 # if defined(__GNUC__) && (__GNUC__ >= 3)
24 // hash_map is not part of the C++ standard anymore;
25 // hash_map.h has been kept though for backward compatibility
26 # include <hash_map.h>
27 # else
28 # include <hash_map>
29 # endif
30 #endif
31 
32 #include <cstdio>
33 #include <list>
34 #include <map>
35 
36 #include "GeomCleaner.h"
37 
38 #include "../system/TimeUtils.h"
39 
40 #include "BKE_global.h"
41 
42 using namespace std;
43 
44 namespace Freestyle {
45 
46 void GeomCleaner::SortIndexedVertexArray(const float *iVertices,
47  unsigned iVSize,
48  const unsigned *iIndices,
49  unsigned iISize,
50  float **oVertices,
51  unsigned **oIndices)
52 {
53  // First, we build a list of IndexVertex:
54  list<IndexedVertex> indexedVertices;
55  unsigned i;
56  for (i = 0; i < iVSize; i += 3) {
57  indexedVertices.emplace_back(Vec3f(iVertices[i], iVertices[i + 1], iVertices[i + 2]), i / 3);
58  }
59 
60  // q-sort
61  indexedVertices.sort();
62 
63  // build the indices mapping array:
64  unsigned *mapIndices = new unsigned[iVSize / 3];
65  *oVertices = new float[iVSize];
66  list<IndexedVertex>::iterator iv;
67  unsigned newIndex = 0;
68  unsigned vIndex = 0;
69  for (iv = indexedVertices.begin(); iv != indexedVertices.end(); iv++) {
70  // Build the final results:
71  (*oVertices)[vIndex] = iv->x();
72  (*oVertices)[vIndex + 1] = iv->y();
73  (*oVertices)[vIndex + 2] = iv->z();
74 
75  mapIndices[iv->index()] = newIndex;
76  newIndex++;
77  vIndex += 3;
78  }
79 
80  // Build the final index array:
81  *oIndices = new unsigned[iISize];
82  for (i = 0; i < iISize; i++) {
83  (*oIndices)[i] = 3 * mapIndices[iIndices[i] / 3];
84  }
85 
86  delete[] mapIndices;
87 }
88 
89 void GeomCleaner::CompressIndexedVertexArray(const float *iVertices,
90  unsigned iVSize,
91  const unsigned *iIndices,
92  unsigned iISize,
93  float **oVertices,
94  unsigned *oVSize,
95  unsigned **oIndices)
96 {
97  // First, we build a list of IndexVertex:
98  vector<Vec3f> vertices;
99  unsigned i;
100  for (i = 0; i < iVSize; i += 3) {
101  vertices.emplace_back(iVertices[i], iVertices[i + 1], iVertices[i + 2]);
102  }
103 
104  unsigned *mapVertex = new unsigned[iVSize];
105  vector<Vec3f>::iterator v = vertices.begin();
106 
107  vector<Vec3f> compressedVertices;
108  Vec3f previous = *v;
109  mapVertex[0] = 0;
110  compressedVertices.push_back(vertices.front());
111 
112  v++;
113  Vec3f current;
114  i = 1;
115  for (; v != vertices.end(); v++) {
116  current = *v;
117  if (current == previous) {
118  mapVertex[i] = compressedVertices.size() - 1;
119  }
120  else {
121  compressedVertices.push_back(current);
122  mapVertex[i] = compressedVertices.size() - 1;
123  }
124  previous = current;
125  i++;
126  }
127 
128  // Builds the resulting vertex array:
129  *oVSize = 3 * compressedVertices.size();
130  *oVertices = new float[*oVSize];
131  i = 0;
132  for (v = compressedVertices.begin(); v != compressedVertices.end(); v++) {
133  (*oVertices)[i] = (*v)[0];
134  (*oVertices)[i + 1] = (*v)[1];
135  (*oVertices)[i + 2] = (*v)[2];
136  i += 3;
137  }
138 
139  // Map the index array:
140  *oIndices = new unsigned[iISize];
141  for (i = 0; i < iISize; i++) {
142  (*oIndices)[i] = 3 * mapVertex[iIndices[i] / 3];
143  }
144 
145  delete[] mapVertex;
146 }
147 
148 void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices,
149  unsigned iVSize,
150  const unsigned *iIndices,
151  unsigned iISize,
152  float **oVertices,
153  unsigned *oVSize,
154  unsigned **oIndices)
155 {
156  // tmp arrays used to store the sorted data:
157  float *tmpVertices;
158  unsigned *tmpIndices;
159 
160  Chronometer chrono;
161  // Sort data
162  chrono.start();
163  GeomCleaner::SortIndexedVertexArray(
164  iVertices, iVSize, iIndices, iISize, &tmpVertices, &tmpIndices);
165  if (G.debug & G_DEBUG_FREESTYLE) {
166  printf("Sorting: %lf sec.\n", chrono.stop());
167  }
168 
169  // compress data
170  chrono.start();
171  GeomCleaner::CompressIndexedVertexArray(
172  tmpVertices, iVSize, tmpIndices, iISize, oVertices, oVSize, oIndices);
173  real duration = chrono.stop();
174  if (G.debug & G_DEBUG_FREESTYLE) {
175  printf("Merging: %lf sec.\n", duration);
176  }
177 
178  // deallocates memory:
179  delete[] tmpVertices;
180  delete[] tmpIndices;
181 }
182 
185 #define _MUL 950706376UL
186 #define _MOD 2147483647UL
187  inline size_t operator()(const Vec3r &p) const
188  {
189  size_t res = ((unsigned long)(p[0] * _MUL)) % _MOD;
190  res = ((res + (unsigned long)(p[1]) * _MUL)) % _MOD;
191  return ((res + (unsigned long)(p[2]) * _MUL)) % _MOD;
192  }
193 #undef _MUL
194 #undef _MOD
195 };
196 
197 void GeomCleaner::CleanIndexedVertexArray(const float *iVertices,
198  unsigned iVSize,
199  const unsigned *iIndices,
200  unsigned iISize,
201  float **oVertices,
202  unsigned *oVSize,
203  unsigned **oIndices)
204 {
205  using cleanHashTable = map<Vec3f, unsigned>;
206  vector<Vec3f> vertices;
207  unsigned i;
208  for (i = 0; i < iVSize; i += 3) {
209  vertices.emplace_back(iVertices[i], iVertices[i + 1], iVertices[i + 2]);
210  }
211 
212  cleanHashTable ht;
213  vector<unsigned> newIndices;
214  vector<Vec3f> newVertices;
215 
216  // elimination of needless points
217  unsigned currentIndex = 0;
218  vector<Vec3f>::const_iterator v = vertices.begin();
219  vector<Vec3f>::const_iterator end = vertices.end();
220  cleanHashTable::const_iterator found;
221  for (; v != end; v++) {
222  found = ht.find(*v);
223  if (found != ht.end()) {
224  // The vertex is already in the new array.
225  newIndices.push_back((*found).second);
226  }
227  else {
228  newVertices.push_back(*v);
229  newIndices.push_back(currentIndex);
230  ht[*v] = currentIndex;
231  currentIndex++;
232  }
233  }
234 
235  // creation of oVertices array:
236  *oVSize = 3 * newVertices.size();
237  *oVertices = new float[*oVSize];
238  currentIndex = 0;
239  end = newVertices.end();
240  for (v = newVertices.begin(); v != end; v++) {
241  (*oVertices)[currentIndex++] = (*v)[0];
242  (*oVertices)[currentIndex++] = (*v)[1];
243  (*oVertices)[currentIndex++] = (*v)[2];
244  }
245 
246  // map new indices:
247  *oIndices = new unsigned[iISize];
248  for (i = 0; i < iISize; i++) {
249  (*oIndices)[i] = 3 * newIndices[iIndices[i] / 3];
250  }
251 }
252 
253 } /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:140
#define _MOD
#define _MUL
Class to define a cleaner of geometry providing a set of useful tools.
ATTR_WARN_UNUSED_RESULT const BMVert * v
struct Vec3f Vec3f
inherits from class Rep
Definition: AppCanvas.cpp:32
double real
Definition: Precision.h:26
size_t operator()(const Vec3r &p) const
#define G(x, y, z)