Visual Computing Library
Loading...
Searching...
No Matches
sphere.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_ALGORITHMS_MESH_CREATE_SPHERE_H
24#define VCL_ALGORITHMS_MESH_CREATE_SPHERE_H
25
26#include "icosahedron.h"
27
28#include <vclib/algorithms/mesh/clean.h>
29#include <vclib/algorithms/mesh/update/transform.h>
30#include <vclib/mesh/requirements.h>
31#include <vclib/space/core/sphere.h>
32
33namespace vcl {
34
54{
55 typedef enum {
56 UV = 0,
57 NORMALIZED_CUBE,
58 SPHERIFIED_CUBE,
59 ICOSAHEDRON
60 } CreateSphereMode;
61
62 CreateSphereMode mode = UV;
63
64 // used for mode = UV
65 uint parallels = 10;
66 uint meridians = 20;
67
68 // used for mode = NORMALIZED_CUBE, SPHERIFIED_CUBE, ICOSAHEDRON
69 uint divisions = 20;
70};
71
72namespace detail {
73
74namespace cts { // Cube to Sphere
75
76const Point3d origins[6] = {
77 Point3d(-1.0, -1.0, -1.0),
78 Point3d(1.0, -1.0, -1.0),
79 Point3d(1.0, -1.0, 1.0),
80 Point3d(-1.0, -1.0, 1.0),
81 Point3d(-1.0, 1.0, -1.0),
82 Point3d(-1.0, -1.0, 1.0)};
83
84const Point3d rights[6] = {
85 Point3d(2.0, 0.0, 0.0),
86 Point3d(0.0, 0.0, 2.0),
87 Point3d(-2.0, 0.0, 0.0),
88 Point3d(0.0, 0.0, -2.0),
89 Point3d(2.0, 0.0, 0.0),
90 Point3d(2.0, 0.0, 0.0)};
91
92const Point3d ups[6] = {
93 Point3d(0.0, 2.0, 0.0),
94 Point3d(0.0, 2.0, 0.0),
95 Point3d(0.0, 2.0, 0.0),
96 Point3d(0.0, 2.0, 0.0),
97 Point3d(0.0, 0.0, 2.0),
98 Point3d(0.0, 0.0, -2.0)};
99
100} // namespace cts
101
102} // namespace detail
103
118template<FaceMeshConcept MeshType>
120 const SphereConcept auto& sp,
121 uint parallels = 10,
122 uint meridians = 20)
123{
124 using VertexType = MeshType::VertexType;
125 using CoordType = VertexType::CoordType;
126 using Facetype = MeshType::FaceType;
127
128 MeshType mesh;
129
130 mesh.addVertex(CoordType(0, 1, 0));
131 for (uint j = 0; j < parallels - 1; ++j) {
132 const double polar = M_PI * double(j + 1) / double(parallels);
133 const double sp = std::sin(polar);
134 const double cp = std::cos(polar);
135 for (uint i = 0; i < meridians; ++i) {
136 const double azimuth = 2.0 * M_PI * double(i) / double(meridians);
137 const double sa = std::sin(azimuth);
138 const double ca = std::cos(azimuth);
139 const double x = sp * ca;
140 const double y = cp;
141 const double z = sp * sa;
142 mesh.addVertex(CoordType(x, y, z));
143 }
144 }
145 mesh.addVertex(CoordType(0, -1, 0));
146
147 for (uint i = 0; i < meridians; ++i) {
148 VertexType* v = &mesh.vertex(0);
149 VertexType* a = &mesh.vertex(i + 1);
150 VertexType* b = &mesh.vertex((i + 1) % meridians + 1);
151 mesh.addFace(0, b, a);
152 }
153
154 for (uint32_t j = 0; j < parallels - 2; ++j) {
155 uint32_t aStart = j * meridians + 1;
156 uint32_t bStart = (j + 1) * meridians + 1;
157 for (uint32_t i = 0; i < meridians; ++i) {
158 VertexType* a = &mesh.vertex(aStart + i);
159 VertexType* a1 = &mesh.vertex(aStart + (i + 1) % meridians);
160 VertexType* b = &mesh.vertex(bStart + i);
161 VertexType* b1 = &mesh.vertex(bStart + (i + 1) % meridians);
162 if constexpr (HasTriangles<MeshType>) {
163 mesh.addFace(a, a1, b1);
164 mesh.addFace(b1, b, a);
165 }
166 else {
167 mesh.addFace(a, a1, b1, b);
168 }
169 }
170 }
171
172 for (uint32_t i = 0; i < meridians; ++i) {
173 VertexType* a = &mesh.vertex(i + meridians * (parallels - 2) + 1);
174 VertexType* b =
175 &mesh.vertex((i + 1) % meridians + meridians * (parallels - 2) + 1);
176 VertexType* v = &mesh.vertex(mesh.vertexNumber() - 1);
177 mesh.addFace(v, a, b);
178 }
179
180 scale(mesh, sp.radius());
181 translate(mesh, sp.center());
182
183 return mesh;
184}
185
199template<FaceMeshConcept MeshType>
201 const SphereConcept auto& sp,
202 uint divisions)
203{
204 using VertexType = MeshType::VertexType;
205 using CoordType = VertexType::CoordType;
206 using Facetype = MeshType::FaceType;
207 using ScalarType = CoordType::ScalarType;
208
209 MeshType mesh;
210
211 const double step = 1.0 / double(divisions);
212 const CoordType step3(step, step, step);
213
214 for (uint face = 0; face < 6; ++face) {
215 const CoordType origin = detail::cts::origins[face].cast<ScalarType>();
216 const CoordType right = detail::cts::rights[face].cast<ScalarType>();
217 const CoordType up = detail::cts::ups[face].cast<ScalarType>();
218 for (uint j = 0; j < divisions + 1; ++j) {
219 const CoordType j3(j, j, j);
220 for (uint i = 0; i < divisions + 1; ++i) {
221 const CoordType i3(i, i, i);
222 const CoordType p =
223 origin + step3.mul(i3.mul(right) + j3.mul(up));
224
225 mesh.addVertex(p.normalized());
226 }
227 }
228 }
229
230 const uint k = divisions + 1;
231 for (uint face = 0; face < 6; ++face) {
232 for (uint j = 0; j < divisions; ++j) {
233 const bool bottom = j < (divisions / 2);
234 for (uint i = 0; i < divisions; ++i) {
235 const bool left = i < (divisions / 2);
236 VertexType* a = &mesh.vertex((face * k + j) * k + i);
237 VertexType* b = &mesh.vertex((face * k + j) * k + i + 1);
238 VertexType* c = &mesh.vertex((face * k + j + 1) * k + i);
239 VertexType* d = &mesh.vertex((face * k + j + 1) * k + i + 1);
240
241 if constexpr (HasTriangles<MeshType>) {
242 if (bottom ^ left) {
243 mesh.addFace(a, c, b);
244 mesh.addFace(c, d, b);
245 }
246 else {
247 mesh.addFace(a, c, d);
248 mesh.addFace(a, d, b);
249 }
250 }
251 else {
252 mesh.addFace(a, c, d, b);
253 }
254 }
255 }
256 }
257
258 scale(mesh, sp.radius());
259 translate(mesh, sp.center());
260
261 return mesh;
262}
263
277template<FaceMeshConcept MeshType>
279 const SphereConcept auto& sp,
280 uint divisions)
281{
282 using VertexType = MeshType::VertexType;
283 using CoordType = VertexType::CoordType;
284 using ScalarType = CoordType::ScalarType;
285 using Facetype = MeshType::FaceType;
286
287 MeshType mesh;
288
289 const double step = 1.0 / double(divisions);
290 const CoordType step3(step, step, step);
291
292 for (uint face = 0; face < 6; ++face) {
293 const CoordType origin = detail::cts::origins[face].cast<ScalarType>();
294 const CoordType right = detail::cts::rights[face].cast<ScalarType>();
295 const CoordType up = detail::cts::ups[face].cast<ScalarType>();
296 for (uint j = 0; j < divisions + 1; ++j) {
297 const CoordType j3(j, j, j);
298 for (uint i = 0; i < divisions + 1; ++i) {
299 const CoordType i3(i, i, i);
300 const CoordType p =
301 origin + step3.mul(i3.mul(right) + j3.mul(up));
302 const CoordType p2 = p.mul(p);
303 const CoordType n(
304 p.x() * std::sqrt(
305 1.0 - 0.5 * (p2.y() + p2.z()) +
306 p2.y() * p2.z() / 3.0),
307 p.y() * std::sqrt(
308 1.0 - 0.5 * (p2.z() + p2.x()) +
309 p2.z() * p2.x() / 3.0),
310 p.z() * std::sqrt(
311 1.0 - 0.5 * (p2.x() + p2.y()) +
312 p2.x() * p2.y() / 3.0));
313 mesh.addVertex(n);
314 }
315 }
316 }
317
318 const uint k = divisions + 1;
319 for (uint face = 0; face < 6; ++face) {
320 for (uint j = 0; j < divisions; ++j) {
321 const bool bottom = j < (divisions / 2);
322 for (uint i = 0; i < divisions; ++i) {
323 const bool left = i < (divisions / 2);
324 VertexType* a = &mesh.vertex((face * k + j) * k + i);
325 VertexType* b = &mesh.vertex((face * k + j) * k + i + 1);
326 VertexType* c = &mesh.vertex((face * k + j + 1) * k + i);
327 VertexType* d = &mesh.vertex((face * k + j + 1) * k + i + 1);
328 if constexpr (HasTriangles<MeshType>) {
329 if (bottom ^ left) {
330 mesh.addFace(a, c, b);
331 mesh.addFace(c, d, b);
332 }
333 else {
334 mesh.addFace(a, c, d);
335 mesh.addFace(a, d, b);
336 }
337 }
338 else {
339 mesh.addFace(a, c, d, b);
340 }
341 }
342 }
343 }
344
345 scale(mesh, sp.radius());
346 translate(mesh, sp.center());
347
348 return mesh;
349}
350
364template<FaceMeshConcept MeshType>
365MeshType createSphereIcosahedron(const SphereConcept auto& sp, uint divisions)
366{
367 using VertexType = MeshType::VertexType;
368 using CoordType = VertexType::CoordType;
369 using FaceType = MeshType::FaceType;
370
371 MeshType mesh = createIcosahedron<MeshType>(true);
372
373 for (uint d = 0; d < divisions; d++) {
374 uint nf = mesh.faceNumber();
375 for (uint f = 0; f < nf; f++) {
376 FaceType& f0 = mesh.face(f);
377 VertexType& v0 = *f0.vertex(0);
378 VertexType& v1 = *f0.vertex(1);
379 VertexType& v2 = *f0.vertex(2);
380 uint v1id = mesh.index(v1);
381 uint v2id = mesh.index(v2);
382
383 CoordType pa = (v0.coord() + v1.coord());
384 pa.normalize();
385 CoordType pb = (v1.coord() + v2.coord());
386 pb.normalize();
387 CoordType pc = (v2.coord() + v0.coord());
388 pc.normalize();
389 uint vaid = mesh.addVertex(pa);
390 uint vbid = mesh.addVertex(pb);
391 uint vcid = mesh.addVertex(pc);
392
393 f0.setVertex(1, vaid);
394 f0.setVertex(2, vcid);
395 mesh.addFace(vaid, v1id, vbid);
396 mesh.addFace(vcid, vbid, v2id);
397 mesh.addFace(vaid, vbid, vcid);
398 }
399 }
400
402
403 scale(mesh, sp.radius());
404 translate(mesh, sp.center());
405
406 return mesh;
407}
408
424template<FaceMeshConcept MeshType>
426 const SphereConcept auto& sp,
428{
429 MeshType m;
430 switch (args.mode) {
431 case CreateSphereArgs::UV:
432 m = createSphereUV<MeshType>(sp, args.parallels, args.meridians);
433 break;
434 case CreateSphereArgs::NORMALIZED_CUBE:
436 break;
437 case CreateSphereArgs::SPHERIFIED_CUBE:
439 break;
440 case CreateSphereArgs::ICOSAHEDRON:
442 break;
443 }
444
445 return m;
446}
447
460template<FaceMeshConcept MeshType>
461MeshType createSphere()
462{
464}
465
466} // namespace vcl
467
468#endif // VCL_ALGORITHMS_MESH_CREATE_SPHERE_H
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:58
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
Definition per_face.h:40
Concept for types representing spheres in Euclidean space.
Definition sphere.h:64
uint removeDuplicatedVertices(MeshType &m)
Marks as deleted the duplicate vertices of the mesh, by looking only at their spatial positions.
Definition clean.h:301
MeshType createSphereUV(const SphereConcept auto &sp, uint parallels=10, uint meridians=20)
Creates and returns a sphere mesh using the UV mode, starting from a sphere object.
Definition sphere.h:119
MeshType createSphere()
Creates a Sphere Mesh using the UV mode (https://github.com/caosdoar/spheres), centered in (0,...
Definition sphere.h:461
MeshType createSphereIcosahedron(const SphereConcept auto &sp, uint divisions)
Creates and returns a sphere mesh using the icosahedron mode, starting from a sphere object.
Definition sphere.h:365
MeshType createSphereSpherifiedCube(const SphereConcept auto &sp, uint divisions)
Creates and returns a sphere mesh using the spherified cube mode, starting from a sphere object.
Definition sphere.h:278
MeshType createSphereNormalizedCube(const SphereConcept auto &sp, uint divisions)
Creates and returns a sphere mesh using the normalized cube mode, starting from a sphere object.
Definition sphere.h:200
Point3< double > Point3d
A convenience alias for a 3-dimensional Point with double-precision floating-point components.
Definition point.h:804
The CreateSphereArgs structs contains a series of parameters to generate a sphere.
Definition sphere.h:54