Visual Computing Library  devel
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/normal.h>
30#include <vclib/algorithms/mesh/update/transform.h>
31
32#include <vclib/mesh.h>
33#include <vclib/space/core.h>
34
35namespace vcl {
36
56{
57 typedef enum {
58 UV = 0,
59 NORMALIZED_CUBE,
60 SPHERIFIED_CUBE,
61 ICOSAHEDRON
62 } CreateSphereMode;
63
64 CreateSphereMode mode = UV;
65
66 // used for mode = UV
67 uint parallels = 10;
68 uint meridians = 20;
69
70 // used for mode = NORMALIZED_CUBE, SPHERIFIED_CUBE, ICOSAHEDRON
71 uint divisions = 20;
72};
73
74namespace detail {
75
76namespace cts { // Cube to Sphere
77
78const Point3d origins[6] = {
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 Point3d(-1.0, 1.0, -1.0),
84 Point3d(-1.0, -1.0, 1.0)};
85
86const Point3d rights[6] = {
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(0.0, 0.0, -2.0),
91 Point3d(2.0, 0.0, 0.0),
92 Point3d(2.0, 0.0, 0.0)};
93
94const Point3d ups[6] = {
95 Point3d(0.0, 2.0, 0.0),
96 Point3d(0.0, 2.0, 0.0),
97 Point3d(0.0, 2.0, 0.0),
98 Point3d(0.0, 2.0, 0.0),
99 Point3d(0.0, 0.0, 2.0),
100 Point3d(0.0, 0.0, -2.0)};
101
102} // namespace cts
103
104} // namespace detail
105
120template<FaceMeshConcept MeshType>
122 const SphereConcept auto& sp,
123 uint parallels = 10,
124 uint meridians = 20)
125{
126 using VertexType = MeshType::VertexType;
127 using PositionType = VertexType::PositionType;
128 using Facetype = MeshType::FaceType;
129
130 MeshType mesh;
131
132 mesh.addVertex(PositionType(0, 1, 0));
133 for (uint j = 0; j < parallels - 1; ++j) {
134 const double polar = M_PI * double(j + 1) / double(parallels);
135 const double sp = std::sin(polar);
136 const double cp = std::cos(polar);
137 for (uint i = 0; i < meridians; ++i) {
138 const double azimuth = 2.0 * M_PI * double(i) / double(meridians);
139 const double sa = std::sin(azimuth);
140 const double ca = std::cos(azimuth);
141 const double x = sp * ca;
142 const double y = cp;
143 const double z = sp * sa;
144 mesh.addVertex(PositionType(x, y, z));
145 }
146 }
147 mesh.addVertex(PositionType(0, -1, 0));
148
149 for (uint i = 0; i < meridians; ++i) {
150 VertexType* v = &mesh.vertex(0);
151 VertexType* a = &mesh.vertex(i + 1);
152 VertexType* b = &mesh.vertex((i + 1) % meridians + 1);
153 mesh.addFace(0, b, a);
154 }
155
156 for (uint32_t j = 0; j < parallels - 2; ++j) {
157 uint32_t aStart = j * meridians + 1;
158 uint32_t bStart = (j + 1) * meridians + 1;
159 for (uint32_t i = 0; i < meridians; ++i) {
160 VertexType* a = &mesh.vertex(aStart + i);
161 VertexType* a1 = &mesh.vertex(aStart + (i + 1) % meridians);
162 VertexType* b = &mesh.vertex(bStart + i);
163 VertexType* b1 = &mesh.vertex(bStart + (i + 1) % meridians);
164 if constexpr (HasTriangles<MeshType>) {
165 mesh.addFace(a, a1, b1);
166 mesh.addFace(b1, b, a);
167 }
168 else {
169 mesh.addFace(a, a1, b1, b);
170 }
171 }
172 }
173
174 for (uint32_t i = 0; i < meridians; ++i) {
175 VertexType* a = &mesh.vertex(i + meridians * (parallels - 2) + 1);
176 VertexType* b =
177 &mesh.vertex((i + 1) % meridians + meridians * (parallels - 2) + 1);
178 VertexType* v = &mesh.vertex(mesh.vertexNumber() - 1);
179 mesh.addFace(v, a, b);
180 }
181
182 scale(mesh, sp.radius());
183 translate(mesh, sp.center());
184
185 return mesh;
186}
187
201template<FaceMeshConcept MeshType>
203 const SphereConcept auto& sp,
204 uint divisions)
205{
206 using VertexType = MeshType::VertexType;
207 using PositionType = VertexType::PositionType;
208 using Facetype = MeshType::FaceType;
209 using ScalarType = PositionType::ScalarType;
210
211 MeshType mesh;
212
213 const double step = 1.0 / double(divisions);
214 const PositionType step3(step, step, step);
215
216 for (uint face = 0; face < 6; ++face) {
217 const PositionType origin =
218 detail::cts::origins[face].cast<ScalarType>();
219 const PositionType right = detail::cts::rights[face].cast<ScalarType>();
220 const PositionType up = detail::cts::ups[face].cast<ScalarType>();
221 for (uint j = 0; j < divisions + 1; ++j) {
222 const PositionType j3(j, j, j);
223 for (uint i = 0; i < divisions + 1; ++i) {
224 const PositionType i3(i, i, i);
225 const PositionType p =
226 origin + step3.mul(i3.mul(right) + j3.mul(up));
227
228 mesh.addVertex(p.normalized());
229 }
230 }
231 }
232
233 const uint k = divisions + 1;
234 for (uint face = 0; face < 6; ++face) {
235 for (uint j = 0; j < divisions; ++j) {
236 const bool bottom = j < (divisions / 2);
237 for (uint i = 0; i < divisions; ++i) {
238 const bool left = i < (divisions / 2);
239 VertexType* a = &mesh.vertex((face * k + j) * k + i);
240 VertexType* b = &mesh.vertex((face * k + j) * k + i + 1);
241 VertexType* c = &mesh.vertex((face * k + j + 1) * k + i);
242 VertexType* d = &mesh.vertex((face * k + j + 1) * k + i + 1);
243
244 if constexpr (HasTriangles<MeshType>) {
245 if (bottom ^ left) {
246 mesh.addFace(a, c, b);
247 mesh.addFace(c, d, b);
248 }
249 else {
250 mesh.addFace(a, c, d);
251 mesh.addFace(a, d, b);
252 }
253 }
254 else {
255 mesh.addFace(a, c, d, b);
256 }
257 }
258 }
259 }
260
261 scale(mesh, sp.radius());
262 translate(mesh, sp.center());
263
264 return mesh;
265}
266
280template<FaceMeshConcept MeshType>
282 const SphereConcept auto& sp,
283 uint divisions)
284{
285 using VertexType = MeshType::VertexType;
286 using PositionType = VertexType::PositionType;
287 using ScalarType = PositionType::ScalarType;
288 using Facetype = MeshType::FaceType;
289
290 MeshType mesh;
291
292 const double step = 1.0 / double(divisions);
293 const PositionType step3(step, step, step);
294
295 for (uint face = 0; face < 6; ++face) {
296 const PositionType origin =
297 detail::cts::origins[face].cast<ScalarType>();
298 const PositionType right = detail::cts::rights[face].cast<ScalarType>();
299 const PositionType up = detail::cts::ups[face].cast<ScalarType>();
300 for (uint j = 0; j < divisions + 1; ++j) {
301 const PositionType j3(j, j, j);
302 for (uint i = 0; i < divisions + 1; ++i) {
303 const PositionType i3(i, i, i);
304 const PositionType p =
305 origin + step3.mul(i3.mul(right) + j3.mul(up));
306 const PositionType p2 = p.mul(p);
307 const PositionType n(
308 p.x() * std::sqrt(
309 1.0 - 0.5 * (p2.y() + p2.z()) +
310 p2.y() * p2.z() / 3.0),
311 p.y() * std::sqrt(
312 1.0 - 0.5 * (p2.z() + p2.x()) +
313 p2.z() * p2.x() / 3.0),
314 p.z() * std::sqrt(
315 1.0 - 0.5 * (p2.x() + p2.y()) +
316 p2.x() * p2.y() / 3.0));
317 mesh.addVertex(n);
318 }
319 }
320 }
321
322 const uint k = divisions + 1;
323 for (uint face = 0; face < 6; ++face) {
324 for (uint j = 0; j < divisions; ++j) {
325 const bool bottom = j < (divisions / 2);
326 for (uint i = 0; i < divisions; ++i) {
327 const bool left = i < (divisions / 2);
328 VertexType* a = &mesh.vertex((face * k + j) * k + i);
329 VertexType* b = &mesh.vertex((face * k + j) * k + i + 1);
330 VertexType* c = &mesh.vertex((face * k + j + 1) * k + i);
331 VertexType* d = &mesh.vertex((face * k + j + 1) * k + i + 1);
332 if constexpr (HasTriangles<MeshType>) {
333 if (bottom ^ left) {
334 mesh.addFace(a, c, b);
335 mesh.addFace(c, d, b);
336 }
337 else {
338 mesh.addFace(a, c, d);
339 mesh.addFace(a, d, b);
340 }
341 }
342 else {
343 mesh.addFace(a, c, d, b);
344 }
345 }
346 }
347 }
348
349 scale(mesh, sp.radius());
350 translate(mesh, sp.center());
351
352 return mesh;
353}
354
368template<FaceMeshConcept MeshType>
369MeshType createSphereIcosahedron(const SphereConcept auto& sp, uint divisions)
370{
371 using VertexType = MeshType::VertexType;
372 using PositionType = VertexType::PositionType;
373 using FaceType = MeshType::FaceType;
374
375 MeshType mesh = createIcosahedron<MeshType>(true);
376
377 for (uint d = 0; d < divisions; d++) {
378 uint nf = mesh.faceNumber();
379 for (uint f = 0; f < nf; f++) {
380 FaceType& f0 = mesh.face(f);
381 VertexType& v0 = *f0.vertex(0);
382 VertexType& v1 = *f0.vertex(1);
383 VertexType& v2 = *f0.vertex(2);
384 uint v1id = mesh.index(v1);
385 uint v2id = mesh.index(v2);
386
387 PositionType pa = (v0.position() + v1.position());
388 pa.normalize();
389 PositionType pb = (v1.position() + v2.position());
390 pb.normalize();
391 PositionType pc = (v2.position() + v0.position());
392 pc.normalize();
393 uint vaid = mesh.addVertex(pa);
394 uint vbid = mesh.addVertex(pb);
395 uint vcid = mesh.addVertex(pc);
396
397 f0.setVertex(1, vaid);
398 f0.setVertex(2, vcid);
399 mesh.addFace(vaid, v1id, vbid);
400 mesh.addFace(vcid, vbid, v2id);
401 mesh.addFace(vaid, vbid, vcid);
402 }
403 }
404
406
407 scale(mesh, sp.radius());
408 translate(mesh, sp.center());
409
410 return mesh;
411}
412
428template<FaceMeshConcept MeshType>
430 const SphereConcept auto& sp,
432{
433 MeshType m;
434 switch (args.mode) {
435 case CreateSphereArgs::UV:
436 m = createSphereUV<MeshType>(sp, args.parallels, args.meridians);
437 break;
438 case CreateSphereArgs::NORMALIZED_CUBE:
440 break;
441 case CreateSphereArgs::SPHERIFIED_CUBE:
443 break;
444 case CreateSphereArgs::ICOSAHEDRON:
446 break;
447 }
448
449 return m;
450}
451
464template<FaceMeshConcept MeshType>
465MeshType createSphere()
466{
468}
469
470} // namespace vcl
471
472#endif // VCL_ALGORITHMS_MESH_CREATE_SPHERE_H
A class representing a box in N-dimensional space.
Definition box.h:46
PointT center() const
Calculates the center point of the box.
Definition box.h:259
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:55
Definition face_requirements.h:52
A concept representing a Sphere.
Definition sphere.h:127
uint removeDuplicatedVertices(MeshType &m)
Marks as deleted the duplicate vertices of the mesh, by looking only at their spatial positions.
Definition clean.h:211
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:121
MeshType createSphere()
Creates a Sphere Mesh using the UV mode (https://github.com/caosdoar/spheres), centered in (0,...
Definition sphere.h:465
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:369
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:281
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:202
Point3< double > Point3d
A convenience alias for a 3-dimensional Point with double-precision floating-point components.
Definition point.h:779
The CreateSphereArgs structs contains a series of parameters to generate a sphere.
Definition sphere.h:56