Tatooine
sphere.h
Go to the documentation of this file.
1#ifndef TATOOINE_GEOMETRY_SPHERE_H
2#define TATOOINE_GEOMETRY_SPHERE_H
3//==============================================================================
4#include <tatooine/concepts.h>
5#include <tatooine/line.h>
6#include <tatooine/real.h>
7#include <tatooine/tensor.h>
9
10#include <boost/range/adaptor/transformed.hpp>
11#include <boost/range/algorithm/copy.hpp>
12//==============================================================================
13namespace tatooine::geometry {
14//==============================================================================
15template <floating_point Real, size_t N>
16struct sphere : ray_intersectable<Real, N> {
20 using typename parent_type::intersection_type;
22 //============================================================================
23 private:
25 Real m_radius = 1;
26 //============================================================================
27 public:
28 explicit sphere(Real const radius = 1) : m_radius{radius} {}
29 sphere(Real const radius, vec_t const& center)
31 sphere(vec_t const& center, Real const radius)
33 //----------------------------------------------------------------------------
34 sphere(sphere const&) = default;
35 sphere(sphere&&) = default;
36 sphere& operator=(sphere const&) = default;
37 sphere& operator=(sphere&&) = default;
38 //============================================================================
39 auto check_intersection(ray<Real, N> const& r, Real const min_t = 0) const
40 -> optional_intersection_type override {
41 if constexpr (N == 3) {
42 auto const m = r.origin();
43 auto const b = dot(m, r.direction());
44 auto const c = dot(m, m) - radius() * radius();
45
46 // Exit if r’s origin outside s (c > 0) and r pointing away from s (b > 0)
47 if (c > 0 && b > 0) {
48 return {};
49 }
50 auto const discr = b * b - c;
51
52 // A negative discriminant corresponds to ray missing sphere
53 if (discr < 0) {
54 return {};
55 }
56
57 // Ray now found to intersect sphere, compute smallest t value of
58 // intersection
59 auto t = -b - std::sqrt(discr);
60
61 // If t is negative, ray started inside sphere so clamp t to zero
62 if (t < min_t) {
63 return {};
64 }
65
66 auto const hit_pos = r(t);
67 auto const nor = normalize(hit_pos);
68 // vec uv{std::atan2(nor(0), nor(2)) / (2 * M_PI) + M_PI / 2,
69 // std::acos(-nor(1)) / M_PI};
70 return intersection_type{this, r, t, hit_pos, nor};
71 } else {
72 throw std::runtime_error{"sphere ray intersection not implemented for " +
73 std::to_string(N) + " dimensions."};
74 return {};
75 }
76 }
77 //----------------------------------------------------------------------------
78 constexpr auto center() const -> auto const& { return m_center; }
79 constexpr auto center() -> auto& { return m_center; }
80 //----------------------------------------------------------------------------
81 constexpr auto radius() const { return m_radius; }
82 constexpr auto radius() -> auto& { return m_radius; }
83 //----------------------------------------------------------------------------
84 template <typename RandomEngine = std::mt19937_64>
85 auto random_point(RandomEngine&& eng = RandomEngine{
86 std::random_device{}()}) const {
88 auto const u = rand();
89 auto const v = rand();
90 auto const theta = u * 2 * M_PI;
91 auto const phi = std::acos(2 * v - 1);
92 auto const r = std::cbrt(rand()) * m_radius;
93 auto const sin_theta = std::sin(theta);
94 auto const cos_theta = std::cos(theta);
95 auto const sin_phi = std::sin(phi);
96 auto const cos_phi = std::cos(phi);
97 auto const x = r * sin_phi * cos_theta;
98 auto const y = r * sin_phi * sin_theta;
99 auto const z = r * cos_phi;
100 return vec{x, y, z};
101 }
102 //----------------------------------------------------------------------------
103 template <typename RandReal, typename RandEngine>
104 auto random_points(size_t const n,
106 auto ps = std::vector<vec<Real, N>>{};
107 for (size_t i = 0; i < n; ++i) {
108 auto const u = rand();
109 auto const v = rand();
110 auto const theta = u * 2 * M_PI;
111 auto const phi = std::acos(2 * v - 1);
112 auto const r = std::cbrt(rand()) * m_radius / 2;
113 auto const sin_theta = std::sin(theta);
114 auto const cos_theta = std::cos(theta);
115 auto const sin_phi = std::sin(phi);
116 auto const cos_phi = std::cos(phi);
117 auto const x = r * sin_phi * cos_theta;
118 auto const y = r * sin_phi * sin_theta;
119 auto const z = r * cos_phi;
120 ps.emplace_back(x, y, z);
121 }
122 return ps;
123 }
124 //----------------------------------------------------------------------------
125 template <typename RandEngine = std::mt19937_64>
126 auto random_points(size_t const n) const {
128 return random_points(n, rand);
129 }
130};
131//------------------------------------------------------------------------------
132template <floating_point Real0, floating_point Real1, size_t N>
133sphere(Real0 radius, vec<Real1, N>&&)
135template <floating_point Real0, floating_point Real1, size_t N>
136sphere(Real0 radius, vec<Real1, N> const&)
138//------------------------------------------------------------------------------
139template <floating_point Real>
140auto discretize(sphere<Real, 2> const& s, size_t const num_vertices) {
141 using namespace std::ranges;
142 auto radial = linspace<Real>{0.0, M_PI * 2, num_vertices + 1};
143 radial.pop_back();
144
145 auto ellipse = line<Real, 2>{};
146 auto radian_to_cartesian = [&s](auto const t) {
147 return vec{std::cos(t) * s.radius(), std::sin(t) * s.radius()};
148 };
149 auto out_it = std::back_inserter(ellipse);
150 copy(radial | views::transform(radian_to_cartesian), out_it);
151 ellipse.set_closed(true);
152 return ellipse;
153}
154//------------------------------------------------------------------------------
155template <floating_point Real>
156auto discretize(sphere<Real, 3> const& s, size_t num_subdivisions = 0) {
158 using vertex_handle = typename mesh_type::vertex_handle;
159 // Real const X = 0.525731112119133606;
160 // Real const Z = 0.850650808352039932;
161 Real const X = 0.525731112119133606;
162 Real const Z = 0.850650808352039932;
163 auto vertices =
164 std::vector{vec{-X, 0, Z}, vec{X, 0, Z}, vec{-X, 0, -Z}, vec{X, 0, -Z},
165 vec{0, Z, X}, vec{0, Z, -X}, vec{0, -Z, X}, vec{0, -Z, -X},
166 vec{Z, X, 0}, vec{-Z, X, 0}, vec{Z, -X, 0}, vec{-Z, -X, 0}};
167 auto faces = std::vector<std::array<vertex_handle, 3>>{
168 {vertex_handle{0}, vertex_handle{4}, vertex_handle{1}},
169 {vertex_handle{0}, vertex_handle{9}, vertex_handle{4}},
170 {vertex_handle{9}, vertex_handle{5}, vertex_handle{4}},
171 {vertex_handle{4}, vertex_handle{5}, vertex_handle{8}},
172 {vertex_handle{4}, vertex_handle{8}, vertex_handle{1}},
173 {vertex_handle{8}, vertex_handle{10}, vertex_handle{1}},
174 {vertex_handle{8}, vertex_handle{3}, vertex_handle{10}},
175 {vertex_handle{5}, vertex_handle{3}, vertex_handle{8}},
176 {vertex_handle{5}, vertex_handle{2}, vertex_handle{3}},
177 {vertex_handle{2}, vertex_handle{7}, vertex_handle{3}},
178 {vertex_handle{7}, vertex_handle{10}, vertex_handle{3}},
179 {vertex_handle{7}, vertex_handle{6}, vertex_handle{10}},
180 {vertex_handle{7}, vertex_handle{11}, vertex_handle{6}},
181 {vertex_handle{11}, vertex_handle{0}, vertex_handle{6}},
182 {vertex_handle{0}, vertex_handle{1}, vertex_handle{6}},
183 {vertex_handle{6}, vertex_handle{1}, vertex_handle{10}},
184 {vertex_handle{9}, vertex_handle{0}, vertex_handle{11}},
185 {vertex_handle{9}, vertex_handle{11}, vertex_handle{2}},
186 {vertex_handle{9}, vertex_handle{2}, vertex_handle{5}},
187 {vertex_handle{7}, vertex_handle{2}, vertex_handle{11}}};
188 for (size_t i = 0; i < num_subdivisions; ++i) {
189 std::vector<std::array<vertex_handle, 3>> subdivided_faces;
190 using edge_t = std::pair<vertex_handle, vertex_handle>;
191 auto subdivided =
192 std::map<edge_t, size_t>{}; // vertex_handle index on edge
193 for (auto& [v0, v1, v2] : faces) {
194 auto edges = std::array{edge_t{v0, v1}, edge_t{v0, v2}, edge_t{v1, v2}};
195 auto nvs =
196 std::array{vertex_handle{0}, vertex_handle{0}, vertex_handle{0}};
197 size_t i = 0;
198 for (auto& edge : edges) {
199 if (edge.first < edge.second) {
200 std::swap(edge.first, edge.second);
201 }
202 if (subdivided.find(edge) == end(subdivided)) {
203 subdivided[edge] = size(vertices);
204 nvs[i++] = size(vertices);
205 vertices.push_back(normalize(
206 (vertices[edge.first.index()] + vertices[edge.second.index()]) *
207 0.5));
208 } else {
209 nvs[i++] = subdivided[edge];
210 }
211 }
212 subdivided_faces.emplace_back(std::array{v0, nvs[1], nvs[0]});
213 subdivided_faces.emplace_back(std::array{nvs[0], nvs[2], v1});
214 subdivided_faces.emplace_back(std::array{nvs[1], v2, nvs[2]});
215 subdivided_faces.emplace_back(std::array{nvs[0], nvs[1], nvs[2]});
216 }
217 faces = subdivided_faces;
218 }
219 for (auto& v : vertices) {
220 v *= s.radius();
221 }
222 auto m = mesh_type{};
223 for (auto& vertex_handle : vertices) {
224 m.insert_vertex(std::move(vertex_handle) + s.center());
225 }
226 for (auto& f : faces) {
227 m.insert_simplex(f[0], f[1], f[2]);
228 }
229 return m;
230}
231//==============================================================================
232template <std::size_t N>
234
239
240template <typename Real>
242template <typename Real>
244template <typename Real>
246template <typename Real>
248//==============================================================================
249} // namespace tatooine::geometry
250//==============================================================================
251#endif
252
Definition: ellipse.h:11
hyper_ellipse< Real, 2 > ellipse
Definition: ellipse.h:14
auto discretize(hyper_ellipse< Real, NumDimensions > const &s, std::size_t const n=32)
Definition: hyper_ellipse.h:273
auto end(Range &&range)
Definition: iterator_facade.h:322
auto vertices(pointset< Real, NumDimensions > const &ps)
Definition: vertex_container.h:278
constexpr auto normalize(base_tensor< Tensor, T, N > const &t_in) -> vec< T, N >
Definition: tensor_operations.h:100
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
constexpr auto dot(base_tensor< Tensor0, T0, N > const &lhs, base_tensor< Tensor1, T1, N > const &rhs)
Definition: tensor_operations.h:120
Definition: hyper_ellipse.h:12
Definition: sphere.h:16
auto random_points(size_t const n, random::uniform< RandReal, RandEngine > &rand) const
Definition: sphere.h:104
vec_t m_center
Definition: sphere.h:24
sphere(vec_t const &center, Real const radius)
Definition: sphere.h:31
constexpr auto radius() -> auto &
Definition: sphere.h:82
sphere(sphere &&)=default
auto random_point(RandomEngine &&eng=RandomEngine{ std::random_device{}()}) const
Definition: sphere.h:85
auto random_points(size_t const n) const
Definition: sphere.h:126
auto check_intersection(ray< Real, N > const &r, Real const min_t=0) const -> optional_intersection_type override
Definition: sphere.h:39
constexpr auto center() const -> auto const &
Definition: sphere.h:78
sphere(sphere const &)=default
sphere(Real const radius, vec_t const &center)
Definition: sphere.h:29
sphere & operator=(sphere const &)=default
constexpr auto radius() const
Definition: sphere.h:81
Real m_radius
Definition: sphere.h:25
sphere & operator=(sphere &&)=default
constexpr auto center() -> auto &
Definition: sphere.h:79
sphere(Real const radius=1)
Definition: sphere.h:28
Definition: intersection.h:13
Definition: line.h:35
Definition: linspace.h:26
constexpr auto pop_back()
Definition: linspace.h:107
Definition: random.h:15
Definition: ray_intersectable.h:10
std::optional< intersection_type > optional_intersection_type
Definition: ray_intersectable.h:14
intersection< real_type, NumDimensions > intersection_type
Definition: ray_intersectable.h:13
Definition: ray.h:10
auto direction() -> auto &
Definition: ray.h:54
auto origin() -> auto &
Definition: ray.h:41
Definition: unstructured_triangular_grid.h:10
static auto constexpr zeros()
Definition: vec.h:26