-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2711472
commit 91170f5
Showing
3 changed files
with
497 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// Copyright (c) 2024-2024, Oslandia. | ||
// SPDX-License-Identifier: LGPL-2.0-or-later | ||
|
||
#include "SFCGAL/Sphere.h" | ||
#include <CGAL/Polyhedron_incremental_builder_3.h> | ||
#include <cmath> | ||
|
||
namespace SFCGAL { | ||
|
||
using Point_3 = Kernel::Point_3; | ||
using Polyhedron_3 = CGAL::Polyhedron_3<Kernel>; | ||
|
||
// Helper class for building the sphere polyhedron | ||
template <class HDS> | ||
class Sphere_builder : public CGAL::Modifier_base<HDS> { | ||
public: | ||
Sphere_builder(double radius, int num_vertical, int num_horizontal, | ||
Point_3 center = Point_3(0, 0, 0)) | ||
: radius(radius), num_vertical(num_vertical), | ||
num_horizontal(num_horizontal), center(center) | ||
{ | ||
} | ||
|
||
void | ||
operator()(HDS &hds) | ||
{ | ||
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds, true); | ||
|
||
int num_vertices = (num_vertical - 1) * num_horizontal + 2; | ||
int num_faces = num_vertical * num_horizontal * 2; | ||
|
||
B.begin_surface(num_vertices, num_faces); | ||
|
||
// Add vertices | ||
addVertices(B); | ||
|
||
// Add faces | ||
addTopFaces(B); | ||
addMiddleFaces(B); | ||
addBottomFaces(B); | ||
|
||
B.end_surface(); | ||
} | ||
|
||
private: | ||
// Add all vertices of the sphere | ||
void | ||
addVertices(CGAL::Polyhedron_incremental_builder_3<HDS> &B) | ||
{ | ||
// Add top vertex | ||
B.add_vertex(Point_3(center.x(), center.y(), center.z() + radius)); | ||
|
||
// Add middle vertices | ||
for (int i = 1; i < num_vertical; ++i) { | ||
double phi = M_PI * double(i) / double(num_vertical); | ||
double z = radius * std::cos(phi); | ||
double r = radius * std::sin(phi); | ||
for (int j = 0; j < num_horizontal; ++j) { | ||
double theta = 2 * M_PI * double(j) / double(num_horizontal); | ||
double x = r * std::cos(theta); | ||
double y = r * std::sin(theta); | ||
B.add_vertex(Point_3(center.x() + x, center.y() + y, center.z() + z)); | ||
} | ||
} | ||
|
||
// Add bottom vertex | ||
B.add_vertex(Point_3(center.x(), center.y(), center.z() - radius)); | ||
} | ||
|
||
// Add faces connecting the top vertex to the first ring of vertices | ||
void | ||
addTopFaces(CGAL::Polyhedron_incremental_builder_3<HDS> &B) | ||
{ | ||
for (int j = 0; j < num_horizontal; ++j) { | ||
B.begin_facet(); | ||
B.add_vertex_to_facet(0); | ||
B.add_vertex_to_facet(1 + (j + 1) % num_horizontal); | ||
B.add_vertex_to_facet(1 + j); | ||
B.end_facet(); | ||
} | ||
} | ||
|
||
// Add faces for the middle rings of vertices | ||
void | ||
addMiddleFaces(CGAL::Polyhedron_incremental_builder_3<HDS> &B) | ||
{ | ||
for (int i = 1; i < num_vertical - 1; ++i) { | ||
for (int j = 0; j < num_horizontal; ++j) { | ||
int current = 1 + (i - 1) * num_horizontal + j; | ||
int next = 1 + (i - 1) * num_horizontal + (j + 1) % num_horizontal; | ||
int below_current = 1 + i * num_horizontal + j; | ||
int below_next = 1 + i * num_horizontal + (j + 1) % num_horizontal; | ||
|
||
B.begin_facet(); | ||
B.add_vertex_to_facet(current); | ||
B.add_vertex_to_facet(next); | ||
B.add_vertex_to_facet(below_next); | ||
B.end_facet(); | ||
|
||
B.begin_facet(); | ||
B.add_vertex_to_facet(current); | ||
B.add_vertex_to_facet(below_next); | ||
B.add_vertex_to_facet(below_current); | ||
B.end_facet(); | ||
} | ||
} | ||
} | ||
|
||
// Add faces connecting the bottom vertex to the last ring of vertices | ||
void | ||
addBottomFaces(CGAL::Polyhedron_incremental_builder_3<HDS> &B) | ||
{ | ||
int last_vertex = (num_vertical - 1) * num_horizontal + 1; | ||
int last_row = 1 + (num_vertical - 2) * num_horizontal; | ||
for (int j = 0; j < num_horizontal; ++j) { | ||
B.begin_facet(); | ||
B.add_vertex_to_facet(last_vertex); | ||
B.add_vertex_to_facet(last_row + j); | ||
B.add_vertex_to_facet(last_row + (j + 1) % num_horizontal); | ||
B.end_facet(); | ||
} | ||
} | ||
|
||
double radius; | ||
int num_vertical; | ||
int num_horizontal; | ||
Point_3 center; | ||
}; | ||
|
||
Sphere::Sphere(const Kernel::FT &radius, const Point_3 ¢er, | ||
int num_vertical, int num_horizontal) | ||
: m_radius(radius), m_center(center), m_num_vertical(num_vertical), | ||
m_num_horizontal(num_horizontal) | ||
{ | ||
} | ||
|
||
Sphere & | ||
Sphere::operator=(Sphere other) | ||
{ | ||
std::swap(m_radius, other.m_radius); | ||
std::swap(m_center, other.m_center); | ||
std::swap(m_num_vertical, other.m_num_vertical); | ||
std::swap(m_num_horizontal, other.m_num_horizontal); | ||
std::swap(m_polyhedron, other.m_polyhedron); | ||
std::swap(m_points, other.m_points); | ||
return *this; | ||
} | ||
|
||
void | ||
Sphere::invalidateCache() | ||
{ | ||
m_polyhedron.reset(); | ||
m_points.reset(); | ||
} | ||
|
||
// Generate the polyhedron representation of the sphere | ||
Polyhedron_3 | ||
Sphere::generateSpherePolyhedron() | ||
{ | ||
Polyhedron_3 P; | ||
Sphere_builder<Polyhedron_3::HalfedgeDS> builder( | ||
CGAL::to_double(m_radius), m_num_vertical, m_num_horizontal, m_center); | ||
P.delegate(builder); | ||
return P; | ||
} | ||
|
||
Polyhedron_3 | ||
Sphere::generatePolyhedron() | ||
{ | ||
if (!m_polyhedron) { | ||
m_polyhedron = generateSpherePolyhedron(); | ||
} | ||
return *m_polyhedron; | ||
} | ||
|
||
std::vector<Point_3> | ||
Sphere::generatePoints() | ||
{ | ||
if (!m_points) { | ||
m_points = generateSpherePoints(); | ||
} | ||
return *m_points; | ||
} | ||
|
||
// Generate points on the sphere's surface | ||
std::vector<Point_3> | ||
Sphere::generateSpherePoints() | ||
{ | ||
std::vector<Point_3> points; | ||
points.reserve(m_num_vertical * m_num_horizontal); | ||
|
||
Kernel::FT d_lat = CGAL_PI / (m_num_vertical - 1); | ||
Kernel::FT d_lon = 2 * CGAL_PI / m_num_horizontal; | ||
|
||
for (int i = 0; i < m_num_vertical; ++i) { | ||
Kernel::FT lat = CGAL_PI / 2 - i * d_lat; | ||
Kernel::FT z = m_radius * std::sin(CGAL::to_double(lat)); | ||
Kernel::FT r = m_radius * std::cos(CGAL::to_double(lat)); | ||
for (int j = 0; j < m_num_horizontal; ++j) { | ||
Kernel::FT lon = j * d_lon; | ||
points.emplace_back(m_center.x() + r * std::cos(CGAL::to_double(lon)), | ||
m_center.y() + r * std::sin(CGAL::to_double(lon)), | ||
m_center.z() + z); | ||
} | ||
} | ||
return points; | ||
} | ||
|
||
} // namespace SFCGAL |
Oops, something went wrong.