1#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Point4D {
6 pub x: f64,
7 pub y: f64,
8 pub z: f64,
9 pub w: f64,
10}
11
12impl Point4D {
13 pub fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
14 Self { x, y, z, w }
15 }
16
17 pub fn origin() -> Self {
18 Self::new(0.0, 0.0, 0.0, 0.0)
19 }
20
21 pub fn distance(&self, other: &Self) -> f64 {
23 let dx = self.x - other.x;
24 let dy = self.y - other.y;
25 let dz = self.z - other.z;
26 let dw = self.w - other.w;
27 (dx * dx + dy * dy + dz * dz + dw * dw).sqrt()
28 }
29
30 pub fn norm(&self) -> f64 {
32 (self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w).sqrt()
33 }
34
35 pub fn add(&self, other: &Self) -> Self {
37 Self::new(
38 self.x + other.x,
39 self.y + other.y,
40 self.z + other.z,
41 self.w + other.w,
42 )
43 }
44
45 pub fn scale(&self, scalar: f64) -> Self {
47 Self::new(
48 self.x * scalar,
49 self.y * scalar,
50 self.z * scalar,
51 self.w * scalar,
52 )
53 }
54
55 pub fn dot(&self, other: &Self) -> f64 {
57 self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
58 }
59}
60
61pub type Vector4D = Point4D;
63
64#[derive(Debug, Clone, Copy)]
66pub struct Matrix4x4 {
67 pub data: [[f64; 4]; 4],
68}
69
70impl Matrix4x4 {
71 pub fn identity() -> Self {
72 Self {
73 data: [
74 [1.0, 0.0, 0.0, 0.0],
75 [0.0, 1.0, 0.0, 0.0],
76 [0.0, 0.0, 1.0, 0.0],
77 [0.0, 0.0, 0.0, 1.0],
78 ],
79 }
80 }
81
82 pub fn zeros() -> Self {
83 Self {
84 data: [[0.0; 4]; 4],
85 }
86 }
87
88 pub fn transform(&self, point: &Point4D) -> Point4D {
90 Point4D::new(
91 self.data[0][0] * point.x
92 + self.data[0][1] * point.y
93 + self.data[0][2] * point.z
94 + self.data[0][3] * point.w,
95 self.data[1][0] * point.x
96 + self.data[1][1] * point.y
97 + self.data[1][2] * point.z
98 + self.data[1][3] * point.w,
99 self.data[2][0] * point.x
100 + self.data[2][1] * point.y
101 + self.data[2][2] * point.z
102 + self.data[2][3] * point.w,
103 self.data[3][0] * point.x
104 + self.data[3][1] * point.y
105 + self.data[3][2] * point.z
106 + self.data[3][3] * point.w,
107 )
108 }
109
110 pub fn multiply(&self, other: &Self) -> Self {
112 let mut result = Self::zeros();
113 for i in 0..4 {
114 for j in 0..4 {
115 for k in 0..4 {
116 result.data[i][j] += self.data[i][k] * other.data[k][j];
117 }
118 }
119 }
120 result
121 }
122
123 pub fn rotation_xy(angle: f64) -> Self {
125 let cos_a = angle.cos();
126 let sin_a = angle.sin();
127 Self {
128 data: [
129 [cos_a, -sin_a, 0.0, 0.0],
130 [sin_a, cos_a, 0.0, 0.0],
131 [0.0, 0.0, 1.0, 0.0],
132 [0.0, 0.0, 0.0, 1.0],
133 ],
134 }
135 }
136
137 pub fn rotation_zw(angle: f64) -> Self {
139 let cos_a = angle.cos();
140 let sin_a = angle.sin();
141 Self {
142 data: [
143 [1.0, 0.0, 0.0, 0.0],
144 [0.0, 1.0, 0.0, 0.0],
145 [0.0, 0.0, cos_a, -sin_a],
146 [0.0, 0.0, sin_a, cos_a],
147 ],
148 }
149 }
150
151 pub fn rotation_xw(angle: f64) -> Self {
153 let cos_a = angle.cos();
154 let sin_a = angle.sin();
155 Self {
156 data: [
157 [cos_a, 0.0, 0.0, -sin_a],
158 [0.0, 1.0, 0.0, 0.0],
159 [0.0, 0.0, 1.0, 0.0],
160 [sin_a, 0.0, 0.0, cos_a],
161 ],
162 }
163 }
164
165 pub fn rotation_yw(angle: f64) -> Self {
167 let cos_a = angle.cos();
168 let sin_a = angle.sin();
169 Self {
170 data: [
171 [1.0, 0.0, 0.0, 0.0],
172 [0.0, cos_a, 0.0, -sin_a],
173 [0.0, 0.0, 1.0, 0.0],
174 [0.0, sin_a, 0.0, cos_a],
175 ],
176 }
177 }
178
179 pub fn scale(factor: f64) -> Self {
181 Self {
182 data: [
183 [factor, 0.0, 0.0, 0.0],
184 [0.0, factor, 0.0, 0.0],
185 [0.0, 0.0, factor, 0.0],
186 [0.0, 0.0, 0.0, factor],
187 ],
188 }
189 }
190
191 pub fn translation(dx: f64, dy: f64, dz: f64, dw: f64) -> Self {
193 Self {
194 data: [
195 [1.0, 0.0, 0.0, dx],
196 [0.0, 1.0, 0.0, dy],
197 [0.0, 0.0, 1.0, dz],
198 [0.0, 0.0, 0.0, 1.0 + dw],
199 ],
200 }
201 }
202}
203
204pub struct Projection4Dto3D {
206 pub viewer_distance: f64,
208}
209
210impl Projection4Dto3D {
211 pub fn new(viewer_distance: f64) -> Self {
212 Self { viewer_distance }
213 }
214
215 pub fn project(&self, point: &Point4D) -> (f64, f64, f64) {
218 let w_factor = 1.0 / (self.viewer_distance - point.w);
219 (point.x * w_factor, point.y * w_factor, point.z * w_factor)
220 }
221
222 pub fn project_orthographic(&self, point: &Point4D) -> (f64, f64, f64) {
224 (point.x, point.y, point.z)
225 }
226
227 pub fn project_stereographic(&self, point: &Point4D) -> (f64, f64, f64) {
229 let denom = 1.0 - point.w;
230 if denom.abs() < 1e-10 {
231 return (point.x * 1000.0, point.y * 1000.0, point.z * 1000.0);
233 }
234 (point.x / denom, point.y / denom, point.z / denom)
235 }
236}
237
238pub struct Tesseract {
240 pub vertices: Vec<Point4D>,
241 pub edges: Vec<(usize, usize)>,
242 pub faces: Vec<Vec<usize>>, pub cells: Vec<Vec<usize>>, }
245
246impl Default for Tesseract {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251
252impl Tesseract {
253 pub fn new() -> Self {
255 let mut vertices = Vec::new();
256
257 for i in 0..16 {
259 let x = if i & 1 == 0 { -1.0 } else { 1.0 };
260 let y = if i & 2 == 0 { -1.0 } else { 1.0 };
261 let z = if i & 4 == 0 { -1.0 } else { 1.0 };
262 let w = if i & 8 == 0 { -1.0 } else { 1.0 };
263 vertices.push(Point4D::new(x, y, z, w));
264 }
265
266 let mut edges = Vec::new();
268 for i in 0..16_usize {
269 for j in (i + 1)..16_usize {
270 let diff: u32 = (i as u32) ^ (j as u32);
272 if diff.count_ones() == 1 {
273 edges.push((i, j));
274 }
275 }
276 }
277
278 let mut faces = Vec::new();
280 for fix_mask in 0..16_u32 {
282 if fix_mask.count_ones() == 2 {
283 let mut face = Vec::new();
284 for i in 0..16_usize {
285 if (i as u32 & fix_mask) == fix_mask || (i as u32 & fix_mask) == 0 {
286 face.push(i);
287 }
288 }
289 if face.len() == 4 {
290 faces.push(face);
291 }
292 }
293 }
294
295 let mut cells = Vec::new();
298
299 for coord in 0..4_u32 {
301 for sign in [0_u32, 1_u32] {
302 let mut cell = Vec::new();
303 for i in 0..16_usize {
304 let bit = (i as u32 >> coord) & 1;
305 if bit == sign {
306 cell.push(i);
307 }
308 }
309 if cell.len() == 8 {
310 cells.push(cell);
311 }
312 }
313 }
314
315 Self {
316 vertices,
317 edges,
318 faces,
319 cells,
320 }
321 }
322
323 pub fn transform(&mut self, matrix: &Matrix4x4) {
325 for vertex in &mut self.vertices {
326 *vertex = matrix.transform(vertex);
327 }
328 }
329
330 pub fn stats(&self) -> TesseractStats {
332 TesseractStats {
333 vertices: self.vertices.len(),
334 edges: self.edges.len(),
335 faces: self.faces.len(),
336 cells: self.cells.len(),
337 }
338 }
339}
340
341#[derive(Debug)]
342pub struct TesseractStats {
343 pub vertices: usize,
344 pub edges: usize,
345 pub faces: usize,
346 pub cells: usize,
347}
348
349pub struct Cell24 {
351 pub vertices: Vec<Point4D>,
352 pub edges: Vec<(usize, usize)>,
353}
354
355impl Default for Cell24 {
356 fn default() -> Self {
357 Self::new()
358 }
359}
360
361impl Cell24 {
362 pub fn new() -> Self {
364 let mut vertices = Vec::new();
365
366 let coords = vec![
368 (1.0, 1.0, 0.0, 0.0),
369 (1.0, -1.0, 0.0, 0.0),
370 (-1.0, 1.0, 0.0, 0.0),
371 (-1.0, -1.0, 0.0, 0.0),
372 (1.0, 0.0, 1.0, 0.0),
373 (1.0, 0.0, -1.0, 0.0),
374 (-1.0, 0.0, 1.0, 0.0),
375 (-1.0, 0.0, -1.0, 0.0),
376 (1.0, 0.0, 0.0, 1.0),
377 (1.0, 0.0, 0.0, -1.0),
378 (-1.0, 0.0, 0.0, 1.0),
379 (-1.0, 0.0, 0.0, -1.0),
380 (0.0, 1.0, 1.0, 0.0),
381 (0.0, 1.0, -1.0, 0.0),
382 (0.0, -1.0, 1.0, 0.0),
383 (0.0, -1.0, -1.0, 0.0),
384 (0.0, 1.0, 0.0, 1.0),
385 (0.0, 1.0, 0.0, -1.0),
386 (0.0, -1.0, 0.0, 1.0),
387 (0.0, -1.0, 0.0, -1.0),
388 (0.0, 0.0, 1.0, 1.0),
389 (0.0, 0.0, 1.0, -1.0),
390 (0.0, 0.0, -1.0, 1.0),
391 (0.0, 0.0, -1.0, -1.0),
392 ];
393
394 for (x, y, z, w) in coords {
395 vertices.push(Point4D::new(x, y, z, w));
396 }
397
398 let mut edges = Vec::new();
400 for i in 0..24 {
401 for j in (i + 1)..24 {
402 let dist = vertices[i].distance(&vertices[j]);
403 if (dist - 2.0_f64.sqrt()).abs() < 0.01 {
404 edges.push((i, j));
405 }
406 }
407 }
408
409 Self { vertices, edges }
410 }
411
412 pub fn transform(&mut self, matrix: &Matrix4x4) {
413 for vertex in &mut self.vertices {
414 *vertex = matrix.transform(vertex);
415 }
416 }
417}
418
419pub struct Simplex4D {
421 pub vertices: Vec<Point4D>,
422 pub edges: Vec<(usize, usize)>,
423}
424
425impl Default for Simplex4D {
426 fn default() -> Self {
427 Self::new()
428 }
429}
430
431impl Simplex4D {
432 pub fn new() -> Self {
434 let sqrt5 = 5.0_f64.sqrt();
436 let vertices = vec![
437 Point4D::new(1.0, 1.0, 1.0, -1.0 / sqrt5),
438 Point4D::new(1.0, -1.0, -1.0, -1.0 / sqrt5),
439 Point4D::new(-1.0, 1.0, -1.0, -1.0 / sqrt5),
440 Point4D::new(-1.0, -1.0, 1.0, -1.0 / sqrt5),
441 Point4D::new(0.0, 0.0, 0.0, 4.0 / sqrt5),
442 ];
443
444 let mut edges = Vec::new();
446 for i in 0..5 {
447 for j in (i + 1)..5 {
448 edges.push((i, j));
449 }
450 }
451
452 Self { vertices, edges }
453 }
454}
455
456pub struct RigidBody4D {
458 pub position: Point4D,
459 pub velocity: Vector4D,
460 pub acceleration: Vector4D,
461 pub rotation: Matrix4x4,
462 pub angular_velocity: f64, }
464
465impl RigidBody4D {
466 pub fn new(position: Point4D) -> Self {
467 Self {
468 position,
469 velocity: Vector4D::origin(),
470 acceleration: Vector4D::origin(),
471 rotation: Matrix4x4::identity(),
472 angular_velocity: 0.0,
473 }
474 }
475
476 pub fn update(&mut self, dt: f64) {
478 self.velocity = self.velocity.add(&self.acceleration.scale(dt));
480
481 self.position = self.position.add(&self.velocity.scale(dt));
483
484 let rot = Matrix4x4::rotation_xy(self.angular_velocity * dt);
486 self.rotation = self.rotation.multiply(&rot);
487 }
488}
489
490pub struct AsciiRenderer3D {
492 pub width: usize,
493 pub height: usize,
494 pub scale: f64,
495}
496
497impl AsciiRenderer3D {
498 pub fn new(width: usize, height: usize, scale: f64) -> Self {
499 Self {
500 width,
501 height,
502 scale,
503 }
504 }
505
506 fn to_screen(&self, x: f64, y: f64, _z: f64) -> (usize, usize) {
508 let sx = ((x * self.scale) + (self.width as f64 / 2.0)) as i32;
509 let sy = ((y * self.scale) + (self.height as f64 / 2.0)) as i32;
510 (
511 sx.max(0).min(self.width as i32 - 1) as usize,
512 sy.max(0).min(self.height as i32 - 1) as usize,
513 )
514 }
515
516 pub fn render_edges(
518 &self,
519 vertices_3d: &[(f64, f64, f64)],
520 edges: &[(usize, usize)],
521 ) -> Vec<String> {
522 let mut buffer = vec![vec![' '; self.width]; self.height];
523
524 for (x, y, z) in vertices_3d {
526 let (sx, sy) = self.to_screen(*x, *y, *z);
527 if sy < self.height && sx < self.width {
528 buffer[sy][sx] = '●';
529 }
530 }
531
532 for (i, j) in edges {
534 if *i < vertices_3d.len() && *j < vertices_3d.len() {
535 let (x1, y1, z1) = vertices_3d[*i];
536 let (x2, y2, z2) = vertices_3d[*j];
537
538 for t in 0..5 {
540 let t_norm = t as f64 / 4.0;
541 let x = x1 + (x2 - x1) * t_norm;
542 let y = y1 + (y2 - y1) * t_norm;
543 let z = z1 + (z2 - z1) * t_norm;
544
545 let (sx, sy) = self.to_screen(x, y, z);
546 if sy < self.height && sx < self.width && buffer[sy][sx] == ' ' {
547 buffer[sy][sx] = '·';
548 }
549 }
550 }
551 }
552
553 buffer.iter().map(|row| row.iter().collect()).collect()
554 }
555}
556
557#[cfg(test)]
558mod tests {
559 use super::*;
560 use std::f64::consts::PI;
561
562 #[test]
563 fn test_point4d_distance() {
564 let p1 = Point4D::new(1.0, 0.0, 0.0, 0.0);
565 let p2 = Point4D::new(0.0, 1.0, 0.0, 0.0);
566 let dist = p1.distance(&p2);
567 assert!((dist - 2.0_f64.sqrt()).abs() < 1e-10);
568 }
569
570 #[test]
571 fn test_tesseract_structure() {
572 let tesseract = Tesseract::new();
573 let stats = tesseract.stats();
574
575 assert_eq!(stats.vertices, 16);
576 assert_eq!(stats.edges, 32);
577 assert_eq!(stats.cells, 8);
578 }
579
580 #[test]
581 fn test_rotation_4d() {
582 let p = Point4D::new(1.0, 0.0, 0.0, 0.0);
583 let rot = Matrix4x4::rotation_xy(PI / 2.0);
584 let rotated = rot.transform(&p);
585
586 assert!(rotated.x.abs() < 1e-10);
587 assert!((rotated.y - 1.0).abs() < 1e-10);
588 }
589
590 #[test]
591 fn test_24cell_vertices() {
592 let cell = Cell24::new();
593 assert_eq!(cell.vertices.len(), 24);
594
595 for v in &cell.vertices {
597 let dist = v.norm();
598 assert!((dist - 2.0_f64.sqrt()).abs() < 0.01);
599 }
600 }
601
602 #[test]
603 fn test_projection() {
604 let proj = Projection4Dto3D::new(4.0);
605 let p4d = Point4D::new(1.0, 1.0, 1.0, 1.0);
606 let (x, _y, _z) = proj.project(&p4d);
607
608 assert!((x - 1.0 / 3.0).abs() < 1e-10);
610 }
611}