15#include <boost/functional/hash.hpp>
16#include <unordered_map>
35 const size_t nSubdivisions)
const {
39 for(
size_t i = 0; i < nSubdivisions; i++) {
40 nVertices += (nTriangles * 3) / 2;
41 nTriangles = nTriangles * 4;
50 template <
typename DT,
typename IT>
57 const size_t &icosphereIndex,
58 const size_t &nVerticesPerIcosphere,
59 const size_t &nTrianglesPerIcosphere,
60 const DT *centers)
const;
65 template <
typename DT,
typename IT>
72 const size_t &nSubdivisions)
const;
77 template <
typename DT,
typename IT>
84 const size_t &nSpheres,
85 const size_t &nSubdivisions,
90 DT *normals =
nullptr)
const;
98 template <
typename DT,
typename IT>
99 IT addVertex(
const DT &x,
103 IT &vertexIndex)
const {
104 IT cIndex = vertexIndex * 3;
106 DT length = std::sqrt(x * x + y * y + z * z);
107 vertexCoords[cIndex] = x / length;
108 vertexCoords[cIndex + 1] = y / length;
109 vertexCoords[cIndex + 2] = z / length;
111 return vertexIndex++;
120 IT addTriangle(
const IT &i,
123 IT *connectivityList,
124 IT &triangleIndex)
const {
125 IT cIndex = triangleIndex * 3;
126 connectivityList[cIndex + 0] = i;
127 connectivityList[cIndex + 1] = j;
128 connectivityList[cIndex + 2] = k;
129 return triangleIndex++;
138 template <
typename DT,
typename IT>
142 std::unordered_map<std::pair<IT, IT>, IT, boost::hash<std::pair<IT, IT>>>
145 IT &vertexIndex)
const {
146 bool firstIsSmaller = i < j;
147 IT a = firstIsSmaller ? i : j;
148 IT b = firstIsSmaller ? j : i;
152 auto it = processedEdges.find({a, b});
153 if(it != processedEdges.end())
161 DT mx = (vertexCoords[aOffset] + vertexCoords[bOffset]) / 2.0;
162 DT my = (vertexCoords[aOffset + 1] + vertexCoords[bOffset + 1]) / 2.0;
163 DT mz = (vertexCoords[aOffset + 2] + vertexCoords[bOffset + 2]) / 2.0;
166 = this->addVertex<DT, IT>(mx, my, mz, vertexCoords, vertexIndex);
167 processedEdges.insert({{a, b}, mIndex});
174template <
typename DT,
typename IT>
178 IT *connectivityList,
181 const size_t &nSubdivisions)
const {
187 const std::string msg
188 =
"Computing Icosphere (S: " + std::to_string(nSubdivisions) +
")";
192 IT triangleIndex = 0;
197 DT t = (1.0 + sqrt(5.0)) / 2.0;
198 this->addVertex<DT, IT>(-1, t, 0, vertexCoords, vertexIndex);
199 this->addVertex<DT, IT>(1, t, 0, vertexCoords, vertexIndex);
200 this->addVertex<DT, IT>(-1, -t, 0, vertexCoords, vertexIndex);
201 this->addVertex<DT, IT>(1, -t, 0, vertexCoords, vertexIndex);
203 this->addVertex<DT, IT>(0, -1, t, vertexCoords, vertexIndex);
204 this->addVertex<DT, IT>(0, 1, t, vertexCoords, vertexIndex);
205 this->addVertex<DT, IT>(0, -1, -t, vertexCoords, vertexIndex);
206 this->addVertex<DT, IT>(0, 1, -t, vertexCoords, vertexIndex);
208 this->addVertex<DT, IT>(t, 0, -1, vertexCoords, vertexIndex);
209 this->addVertex<DT, IT>(t, 0, 1, vertexCoords, vertexIndex);
210 this->addVertex<DT, IT>(-t, 0, -1, vertexCoords, vertexIndex);
211 this->addVertex<DT, IT>(-t, 0, 1, vertexCoords, vertexIndex);
214 this->addTriangle<IT>(0, 11, 5, connectivityList, triangleIndex);
215 this->addTriangle<IT>(0, 5, 1, connectivityList, triangleIndex);
216 this->addTriangle<IT>(0, 1, 7, connectivityList, triangleIndex);
217 this->addTriangle<IT>(0, 7, 10, connectivityList, triangleIndex);
218 this->addTriangle<IT>(0, 10, 11, connectivityList, triangleIndex);
219 this->addTriangle<IT>(1, 5, 9, connectivityList, triangleIndex);
220 this->addTriangle<IT>(5, 11, 4, connectivityList, triangleIndex);
221 this->addTriangle<IT>(11, 10, 2, connectivityList, triangleIndex);
222 this->addTriangle<IT>(10, 7, 6, connectivityList, triangleIndex);
223 this->addTriangle<IT>(7, 1, 8, connectivityList, triangleIndex);
224 this->addTriangle<IT>(3, 9, 4, connectivityList, triangleIndex);
225 this->addTriangle<IT>(3, 4, 2, connectivityList, triangleIndex);
226 this->addTriangle<IT>(3, 2, 6, connectivityList, triangleIndex);
227 this->addTriangle<IT>(3, 6, 8, connectivityList, triangleIndex);
228 this->addTriangle<IT>(3, 8, 9, connectivityList, triangleIndex);
229 this->addTriangle<IT>(4, 9, 5, connectivityList, triangleIndex);
230 this->addTriangle<IT>(2, 4, 11, connectivityList, triangleIndex);
231 this->addTriangle<IT>(6, 2, 10, connectivityList, triangleIndex);
232 this->addTriangle<IT>(8, 6, 7, connectivityList, triangleIndex);
233 this->addTriangle<IT>(9, 8, 1, connectivityList, triangleIndex);
237 if(nSubdivisions > 0) {
239 size_t nVertices = 0;
240 size_t nTriangles = 0;
242 nVertices, nTriangles, nSubdivisions);
244 std::vector<IT> connectivityListTemp(nTriangles * 3, 0);
247 std::unordered_map<std::pair<IT, IT>, IT, boost::hash<std::pair<IT, IT>>>
251 for(
size_t s = 0; s < nSubdivisions; s++) {
254 = s % 2 == 0 ? connectivityList : connectivityListTemp.data();
255 IT *newList = s % 2 != 0 ? connectivityList : connectivityListTemp.data();
258 const size_t nOldTriangles = triangleIndex;
261 for(
size_t i = 0; i < nOldTriangles; i++) {
262 const IT offset = i * 3;
266 = this->addMidVertex(oldList[offset + 0], oldList[offset + 1],
267 processedEdges, vertexCoords, vertexIndex);
269 = this->addMidVertex(oldList[offset + 1], oldList[offset + 2],
270 processedEdges, vertexCoords, vertexIndex);
272 = this->addMidVertex(oldList[offset + 2], oldList[offset + 0],
273 processedEdges, vertexCoords, vertexIndex);
276 this->addTriangle(oldList[offset + 0], a, c, newList, triangleIndex);
277 this->addTriangle(oldList[offset + 1], b, a, newList, triangleIndex);
278 this->addTriangle(oldList[offset + 2], c, b, newList, triangleIndex);
279 this->addTriangle(a, b, c, newList, triangleIndex);
288 if(nSubdivisions > 0 && nSubdivisions % 2 != 0) {
289 size_t n = nTriangles * 3;
290 for(
size_t i = 0; i < n; i++)
291 connectivityList[i] = connectivityListTemp[i];
301template <
typename DT,
typename IT>
303 IT *connectivityList,
304 const size_t &icosphereIndex,
305 const size_t &nVerticesPerIcosphere,
306 const size_t &nTrianglesPerIcosphere,
307 const DT *centers)
const {
308 size_t vertexCoordOffset = icosphereIndex * nVerticesPerIcosphere * 3;
309 size_t connectivityListOffset = icosphereIndex * nTrianglesPerIcosphere * 3;
310 size_t temp = icosphereIndex * 3;
311 const DT ¢erX = centers[temp++];
312 const DT ¢erY = centers[temp++];
313 const DT ¢erZ = centers[temp];
316 for(
size_t i = 0, limit = nVerticesPerIcosphere * 3; i < limit;) {
317 vertexCoords[vertexCoordOffset++] = vertexCoords[i++] + centerX;
318 vertexCoords[vertexCoordOffset++] = vertexCoords[i++] + centerY;
319 vertexCoords[vertexCoordOffset++] = vertexCoords[i++] + centerZ;
323 size_t vertexIdOffset = icosphereIndex * nVerticesPerIcosphere;
324 for(
size_t i = 0, limit = nTrianglesPerIcosphere * 3; i < limit;) {
325 connectivityList[connectivityListOffset++]
326 = connectivityList[i++] + vertexIdOffset;
327 connectivityList[connectivityListOffset++]
328 = connectivityList[i++] + vertexIdOffset;
329 connectivityList[connectivityListOffset++]
330 = connectivityList[i++] + vertexIdOffset;
336template <
typename DT,
typename IT>
340 IT *connectivityList,
343 const size_t &nSpheres,
344 const size_t &nSubdivisions,
352 this->printWrn(
"Number of input points smaller than 1.");
357 size_t nVerticesPerIcosphere, nTrianglesPerIcosphere;
358 if(!this->computeNumberOfVerticesAndTriangles(
359 nVerticesPerIcosphere, nTrianglesPerIcosphere, nSubdivisions))
363 if(!this->computeIcosphere(vertexCoords, connectivityList, nSubdivisions))
367 if(normals !=
nullptr) {
369 this->
printMsg(
"Computing Normals", 0, 0, this->threadNumber_,
372#ifdef TTK_ENABLE_OPENMP
373#pragma omp parallel for num_threads(threadNumber_)
375 for(
size_t i = 0; i < nSpheres; i++) {
376 size_t n = nVerticesPerIcosphere * 3;
377 size_t offset = i * n;
378 for(
size_t j = 0; j < n; j++)
379 normals[offset++] = vertexCoords[j];
387 const std::string transMsg =
"Moving " + std::to_string(nSpheres)
388 +
" Icospheres (R: " + std::to_string(radius)
395 for(
size_t i = 0, j = nVerticesPerIcosphere * 3; i < j; i++) {
396 vertexCoords[i] *= radius;
399#ifdef TTK_ENABLE_OPENMP
400#pragma omp parallel for num_threads(threadNumber_)
402 for(
size_t i = 1; i < nSpheres; i++) {
403 this->translateIcosphere(vertexCoords, connectivityList, i,
404 nVerticesPerIcosphere, nTrianglesPerIcosphere,
409 this->translateIcosphere(vertexCoords, connectivityList, 0,
410 nVerticesPerIcosphere, nTrianglesPerIcosphere,
Minimalist debugging class.
void setDebugMsgPrefix(const std::string &prefix)
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
int computeIcosphere(DT *vertexCoords, IT *connectivityList, const size_t &nSubdivisions) const
~Icosphere() override=default
int computeIcospheres(DT *vertexCoords, IT *connectivityList, const size_t &nSpheres, const size_t &nSubdivisions, const DT &radius, const DT *center, DT *normals=nullptr) const
int computeNumberOfVerticesAndTriangles(size_t &nVertices, size_t &nTriangles, const size_t nSubdivisions) const
int translateIcosphere(DT *vertexCoords, IT *connectivityList, const size_t &icosphereIndex, const size_t &nVerticesPerIcosphere, const size_t &nTrianglesPerIcosphere, const DT *centers) const
printMsg(debug::output::GREEN+" "+debug::output::ENDCOLOR+debug::output::GREEN+"▒"+debug::output::ENDCOLOR+debug::output::GREEN+"▒▒▒▒▒▒▒▒▒▒▒▒▒░"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)