1use crate::core::{
26 algebra::{Matrix4, Point3, UnitQuaternion, Vector2, Vector3},
27 color::{Color, Hsl},
28 math::{aabb::AxisAlignedBoundingBox, frustum::Frustum, Matrix4Ext},
29};
30use std::ops::Range;
31
32#[derive(Clone, Debug)]
34pub struct Line {
35 pub begin: Vector3<f32>,
37 pub end: Vector3<f32>,
39 pub color: Color,
41}
42
43#[derive(Default, Clone, Debug)]
88pub struct SceneDrawingContext {
89 pub lines: Vec<Line>,
91}
92
93impl rapier2d::pipeline::DebugRenderBackend for SceneDrawingContext {
94 fn draw_line(
95 &mut self,
96 _object: rapier2d::pipeline::DebugRenderObject,
97 a: rapier2d::math::Point<rapier2d::math::Real>,
98 b: rapier2d::math::Point<rapier2d::math::Real>,
99 color: [f32; 4],
100 ) {
101 self.add_line(Line {
102 begin: Vector3::new(a.x, a.y, 0.0),
103 end: Vector3::new(b.x, b.y, 0.0),
104 color: Color::from(Hsl::new(color[0], color[1], color[2])),
105 })
106 }
107}
108
109impl rapier3d::pipeline::DebugRenderBackend for SceneDrawingContext {
110 fn draw_line(
111 &mut self,
112 _object: rapier3d::pipeline::DebugRenderObject,
113 a: rapier3d::math::Point<rapier3d::math::Real>,
114 b: rapier3d::math::Point<rapier3d::math::Real>,
115 color: [f32; 4],
116 ) {
117 self.add_line(Line {
118 begin: a.coords,
119 end: b.coords,
120 color: Color::from(Hsl::new(color[0], color[1], color[2])),
121 })
122 }
123}
124
125impl SceneDrawingContext {
126 pub fn draw_frustum(&mut self, frustum: &Frustum, color: Color) {
128 let left_top_front = frustum.left_top_front_corner();
129 let left_bottom_front = frustum.left_bottom_front_corner();
130 let right_bottom_front = frustum.right_bottom_front_corner();
131 let right_top_front = frustum.right_top_front_corner();
132
133 let left_top_back = frustum.left_top_back_corner();
134 let left_bottom_back = frustum.left_bottom_back_corner();
135 let right_bottom_back = frustum.right_bottom_back_corner();
136 let right_top_back = frustum.right_top_back_corner();
137
138 self.add_line(Line {
140 begin: left_top_front,
141 end: right_top_front,
142 color,
143 });
144 self.add_line(Line {
145 begin: right_top_front,
146 end: right_bottom_front,
147 color,
148 });
149 self.add_line(Line {
150 begin: right_bottom_front,
151 end: left_bottom_front,
152 color,
153 });
154 self.add_line(Line {
155 begin: left_bottom_front,
156 end: left_top_front,
157 color,
158 });
159
160 self.add_line(Line {
162 begin: left_top_back,
163 end: right_top_back,
164 color,
165 });
166 self.add_line(Line {
167 begin: right_top_back,
168 end: right_bottom_back,
169 color,
170 });
171 self.add_line(Line {
172 begin: right_bottom_back,
173 end: left_bottom_back,
174 color,
175 });
176 self.add_line(Line {
177 begin: left_bottom_back,
178 end: left_top_back,
179 color,
180 });
181
182 self.add_line(Line {
184 begin: left_top_front,
185 end: left_top_back,
186 color,
187 });
188 self.add_line(Line {
189 begin: right_top_front,
190 end: right_top_back,
191 color,
192 });
193 self.add_line(Line {
194 begin: right_bottom_front,
195 end: right_bottom_back,
196 color,
197 });
198 self.add_line(Line {
199 begin: left_bottom_front,
200 end: left_bottom_back,
201 color,
202 });
203 }
204
205 pub fn draw_aabb(&mut self, aabb: &AxisAlignedBoundingBox, color: Color) {
207 let left_bottom_front = Vector3::new(aabb.min.x, aabb.min.y, aabb.max.z);
208 let left_top_front = Vector3::new(aabb.min.x, aabb.max.y, aabb.max.z);
209 let right_top_front = Vector3::new(aabb.max.x, aabb.max.y, aabb.max.z);
210 let right_bottom_front = Vector3::new(aabb.max.x, aabb.min.y, aabb.max.z);
211
212 let left_bottom_back = Vector3::new(aabb.min.x, aabb.min.y, aabb.min.z);
213 let left_top_back = Vector3::new(aabb.min.x, aabb.max.y, aabb.min.z);
214 let right_top_back = Vector3::new(aabb.max.x, aabb.max.y, aabb.min.z);
215 let right_bottom_back = Vector3::new(aabb.max.x, aabb.min.y, aabb.min.z);
216
217 self.add_line(Line {
219 begin: left_top_front,
220 end: right_top_front,
221 color,
222 });
223 self.add_line(Line {
224 begin: right_top_front,
225 end: right_bottom_front,
226 color,
227 });
228 self.add_line(Line {
229 begin: right_bottom_front,
230 end: left_bottom_front,
231 color,
232 });
233 self.add_line(Line {
234 begin: left_bottom_front,
235 end: left_top_front,
236 color,
237 });
238
239 self.add_line(Line {
241 begin: left_top_back,
242 end: right_top_back,
243 color,
244 });
245 self.add_line(Line {
246 begin: right_top_back,
247 end: right_bottom_back,
248 color,
249 });
250 self.add_line(Line {
251 begin: right_bottom_back,
252 end: left_bottom_back,
253 color,
254 });
255 self.add_line(Line {
256 begin: left_bottom_back,
257 end: left_top_back,
258 color,
259 });
260
261 self.add_line(Line {
263 begin: left_top_front,
264 end: left_top_back,
265 color,
266 });
267 self.add_line(Line {
268 begin: right_top_front,
269 end: right_top_back,
270 color,
271 });
272 self.add_line(Line {
273 begin: right_bottom_front,
274 end: right_bottom_back,
275 color,
276 });
277 self.add_line(Line {
278 begin: left_bottom_front,
279 end: left_bottom_back,
280 color,
281 });
282 }
283
284 pub fn draw_oob(
286 &mut self,
287 aabb: &AxisAlignedBoundingBox,
288 transform: Matrix4<f32>,
289 color: Color,
290 ) {
291 let left_bottom_front = transform
292 .transform_point(&Point3::new(aabb.min.x, aabb.min.y, aabb.max.z))
293 .coords;
294 let left_top_front = transform
295 .transform_point(&Point3::new(aabb.min.x, aabb.max.y, aabb.max.z))
296 .coords;
297 let right_top_front = transform
298 .transform_point(&Point3::new(aabb.max.x, aabb.max.y, aabb.max.z))
299 .coords;
300 let right_bottom_front = transform
301 .transform_point(&Point3::new(aabb.max.x, aabb.min.y, aabb.max.z))
302 .coords;
303
304 let left_bottom_back = transform
305 .transform_point(&Point3::new(aabb.min.x, aabb.min.y, aabb.min.z))
306 .coords;
307 let left_top_back = transform
308 .transform_point(&Point3::new(aabb.min.x, aabb.max.y, aabb.min.z))
309 .coords;
310 let right_top_back = transform
311 .transform_point(&Point3::new(aabb.max.x, aabb.max.y, aabb.min.z))
312 .coords;
313 let right_bottom_back = transform
314 .transform_point(&Point3::new(aabb.max.x, aabb.min.y, aabb.min.z))
315 .coords;
316
317 self.add_line(Line {
319 begin: left_top_front,
320 end: right_top_front,
321 color,
322 });
323 self.add_line(Line {
324 begin: right_top_front,
325 end: right_bottom_front,
326 color,
327 });
328 self.add_line(Line {
329 begin: right_bottom_front,
330 end: left_bottom_front,
331 color,
332 });
333 self.add_line(Line {
334 begin: left_bottom_front,
335 end: left_top_front,
336 color,
337 });
338
339 self.add_line(Line {
341 begin: left_top_back,
342 end: right_top_back,
343 color,
344 });
345 self.add_line(Line {
346 begin: right_top_back,
347 end: right_bottom_back,
348 color,
349 });
350 self.add_line(Line {
351 begin: right_bottom_back,
352 end: left_bottom_back,
353 color,
354 });
355 self.add_line(Line {
356 begin: left_bottom_back,
357 end: left_top_back,
358 color,
359 });
360
361 self.add_line(Line {
363 begin: left_top_front,
364 end: left_top_back,
365 color,
366 });
367 self.add_line(Line {
368 begin: right_top_front,
369 end: right_top_back,
370 color,
371 });
372 self.add_line(Line {
373 begin: right_bottom_front,
374 end: right_bottom_back,
375 color,
376 });
377 self.add_line(Line {
378 begin: left_bottom_front,
379 end: left_bottom_back,
380 color,
381 });
382 }
383
384 pub fn draw_transform(&mut self, matrix: Matrix4<f32>) {
386 let x = matrix.transform_vector(&Vector3::x());
387 let y = matrix.transform_vector(&Vector3::y());
388 let z = matrix.transform_vector(&Vector3::z());
389 let origin = matrix.position();
390 self.add_line(Line {
391 begin: origin,
392 end: origin + x,
393 color: Color::RED,
394 });
395 self.add_line(Line {
396 begin: origin,
397 end: origin + y,
398 color: Color::GREEN,
399 });
400 self.add_line(Line {
401 begin: origin,
402 end: origin + z,
403 color: Color::BLUE,
404 });
405 }
406
407 pub fn draw_triangle(
409 &mut self,
410 a: Vector3<f32>,
411 b: Vector3<f32>,
412 c: Vector3<f32>,
413 color: Color,
414 ) {
415 self.add_line(Line {
416 begin: a,
417 end: b,
418 color,
419 });
420 self.add_line(Line {
421 begin: b,
422 end: c,
423 color,
424 });
425 self.add_line(Line {
426 begin: c,
427 end: a,
428 color,
429 });
430 }
431
432 pub fn draw_pyramid(
434 &mut self,
435 top: Vector3<f32>,
436 a: Vector3<f32>,
437 b: Vector3<f32>,
438 c: Vector3<f32>,
439 d: Vector3<f32>,
440 color: Color,
441 transform: Matrix4<f32>,
442 ) {
443 let top = transform.position() + transform.transform_vector(&top);
444 let a = transform.position() + transform.transform_vector(&a);
445 let b = transform.position() + transform.transform_vector(&b);
446 let c = transform.position() + transform.transform_vector(&c);
447 let d = transform.position() + transform.transform_vector(&d);
448 self.draw_triangle(top, a, b, color);
449 self.draw_triangle(top, b, c, color);
450 self.draw_triangle(top, c, d, color);
451 self.draw_triangle(top, d, a, color);
452 }
453
454 pub fn draw_wire_sphere(
456 &mut self,
457 position: Vector3<f32>,
458 radius: f32,
459 segments: usize,
460 color: Color,
461 ) {
462 let translation = Matrix4::new_translation(&position);
463 self.draw_circle(Default::default(), radius, segments, translation, color);
464 self.draw_circle(
465 Default::default(),
466 radius,
467 segments,
468 translation
469 * UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 90.0f32.to_radians())
470 .to_homogeneous(),
471 color,
472 );
473 self.draw_circle(
474 Default::default(),
475 radius,
476 segments,
477 translation
478 * UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 90.0f32.to_radians())
479 .to_homogeneous(),
480 color,
481 );
482 }
483
484 pub fn draw_circle(
487 &mut self,
488 position: Vector3<f32>,
489 radius: f32,
490 segments: usize,
491 transform: Matrix4<f32>,
492 color: Color,
493 ) {
494 let d_phi = 2.0 * std::f32::consts::PI / segments as f32;
495 for i in 0..segments {
496 let x1 = position.x + radius * (d_phi * i as f32).cos();
497 let y1 = position.y + radius * (d_phi * i as f32).sin();
498 let x2 = position.x + radius * (d_phi * (i + 1) as f32).cos();
499 let y2 = position.y + radius * (d_phi * (i + 1) as f32).sin();
500
501 self.add_line(Line {
502 begin: transform.transform_point(&Point3::new(x1, y1, 0.0)).coords,
503 end: transform.transform_point(&Point3::new(x2, y2, 0.0)).coords,
504 color,
505 })
506 }
507 }
508
509 pub fn draw_circle_segment(
512 &mut self,
513 position: Vector3<f32>,
514 radius: f32,
515 segments: usize,
516 begin_angle: f32,
517 end_angle: f32,
518 transform: Matrix4<f32>,
519 color: Color,
520 ) {
521 let d_angle = 2.0 * std::f32::consts::PI / segments as f32;
522 let mut angle = begin_angle;
523 while angle < end_angle {
524 let x1 = position.x + radius * (angle).cos();
525 let y1 = position.y + radius * (angle).sin();
526 let x2 = position.x + radius * (angle + d_angle).cos();
527 let y2 = position.y + radius * (angle + d_angle).sin();
528
529 self.add_line(Line {
530 begin: transform.transform_point(&Point3::new(x1, y1, 0.0)).coords,
531 end: transform.transform_point(&Point3::new(x2, y2, 0.0)).coords,
532 color,
533 });
534
535 angle += d_angle;
536 }
537 }
538
539 pub fn draw_rectangle(
541 &mut self,
542 half_width: f32,
543 half_height: f32,
544 transform: Matrix4<f32>,
545 color: Color,
546 ) {
547 let a = transform
548 .transform_point(&Point3::new(-half_width, half_height, 0.0))
549 .coords;
550 let b = transform
551 .transform_point(&Point3::new(half_width, half_height, 0.0))
552 .coords;
553 let c = transform
554 .transform_point(&Point3::new(half_width, -half_height, 0.0))
555 .coords;
556 let d = transform
557 .transform_point(&Point3::new(-half_width, -half_height, 0.0))
558 .coords;
559 self.add_line(Line {
560 begin: a,
561 end: b,
562 color,
563 });
564 self.add_line(Line {
565 begin: b,
566 end: c,
567 color,
568 });
569 self.add_line(Line {
570 begin: c,
571 end: d,
572 color,
573 });
574 self.add_line(Line {
575 begin: d,
576 end: a,
577 color,
578 });
579 }
580
581 pub fn draw_sphere(
583 &mut self,
584 position: Vector3<f32>,
585 slices: usize,
586 stacks: usize,
587 radius: f32,
588 color: Color,
589 ) {
590 let d_theta = std::f32::consts::PI / slices as f32;
591 let d_phi = 2.0 * std::f32::consts::PI / stacks as f32;
592
593 for i in 0..stacks {
594 for j in 0..slices {
595 let nj = j + 1;
596 let ni = i + 1;
597
598 let k0 = radius * (d_theta * i as f32).sin();
599 let k1 = (d_phi * j as f32).cos();
600 let k2 = (d_phi * j as f32).sin();
601 let k3 = radius * (d_theta * i as f32).cos();
602
603 let k4 = radius * (d_theta * ni as f32).sin();
604 let k5 = (d_phi * nj as f32).cos();
605 let k6 = (d_phi * nj as f32).sin();
606 let k7 = radius * (d_theta * ni as f32).cos();
607
608 if i != (stacks - 1) {
609 self.draw_triangle(
610 position + Vector3::new(k0 * k1, k0 * k2, k3),
611 position + Vector3::new(k4 * k1, k4 * k2, k7),
612 position + Vector3::new(k4 * k5, k4 * k6, k7),
613 color,
614 );
615 }
616
617 if i != 0 {
618 self.draw_triangle(
619 position + Vector3::new(k4 * k5, k4 * k6, k7),
620 position + Vector3::new(k0 * k5, k0 * k6, k3),
621 position + Vector3::new(k0 * k1, k0 * k2, k3),
622 color,
623 );
624 }
625 }
626 }
627 }
628
629 pub fn draw_sphere_section(
631 &mut self,
632 radius: f32,
633 theta_range: Range<f32>,
634 theta_steps: usize,
635 phi_range: Range<f32>,
636 phi_steps: usize,
637 transform: Matrix4<f32>,
638 color: Color,
639 ) {
640 assert!(theta_range.start < theta_range.end);
641 assert!(phi_range.start < phi_range.end);
642
643 assert_ne!(phi_steps, 0);
644 assert_ne!(theta_steps, 0);
645
646 let theta_step = (theta_range.end - theta_range.start) / theta_steps as f32;
647 let phi_step = (phi_range.end - phi_range.start) / phi_steps as f32;
648
649 fn spherical_to_cartesian(radius: f32, theta: f32, phi: f32) -> Vector3<f32> {
650 Vector3::new(
651 radius * theta.sin() * phi.cos(),
652 radius * theta.cos(),
653 radius * theta.sin() * phi.sin(),
654 )
655 }
656
657 let mut theta = theta_range.start;
658 while theta < theta_range.end {
659 let mut phi = phi_range.start;
660 while phi < phi_range.end {
661 let p0 = transform
662 .transform_point(&Point3::from(spherical_to_cartesian(radius, theta, phi)))
663 .coords;
664 let p1 = transform
665 .transform_point(&Point3::from(spherical_to_cartesian(
666 radius,
667 theta,
668 phi + phi_step,
669 )))
670 .coords;
671 let p2 = transform
672 .transform_point(&Point3::from(spherical_to_cartesian(
673 radius,
674 theta + theta_step,
675 phi + phi_step,
676 )))
677 .coords;
678 let p3 = transform
679 .transform_point(&Point3::from(spherical_to_cartesian(
680 radius,
681 theta + theta_step,
682 phi,
683 )))
684 .coords;
685
686 self.draw_triangle(p0, p1, p2, color);
687 self.draw_triangle(p0, p2, p3, color);
688
689 phi += phi_step;
690 }
691 theta += theta_step;
692 }
693 }
694
695 pub fn draw_cone(
697 &mut self,
698 sides: usize,
699 r: f32,
700 h: f32,
701 transform: Matrix4<f32>,
702 color: Color,
703 cap: bool,
704 ) {
705 let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
706
707 let half_height = h / 2.0;
708
709 for i in 0..sides {
710 let nx0 = (d_phi * i as f32).cos();
711 let ny0 = (d_phi * i as f32).sin();
712 let nx1 = (d_phi * (i + 1) as f32).cos();
713 let ny1 = (d_phi * (i + 1) as f32).sin();
714
715 let x0 = r * nx0;
716 let z0 = r * ny0;
717 let x1 = r * nx1;
718 let z1 = r * ny1;
719
720 if cap {
722 self.draw_triangle(
723 transform
724 .transform_point(&Point3::new(0.0, -half_height, 0.0))
725 .coords,
726 transform
727 .transform_point(&Point3::new(x0, -half_height, z0))
728 .coords,
729 transform
730 .transform_point(&Point3::new(x1, -half_height, z1))
731 .coords,
732 color,
733 );
734 }
735
736 self.draw_triangle(
738 transform
739 .transform_point(&Point3::new(0.0, half_height, 0.0))
740 .coords,
741 transform
742 .transform_point(&Point3::new(x1, -half_height, z1))
743 .coords,
744 transform
745 .transform_point(&Point3::new(x0, -half_height, z0))
746 .coords,
747 color,
748 );
749 }
750 }
751
752 pub fn draw_cylinder(
754 &mut self,
755 sides: usize,
756 r: f32,
757 h: f32,
758 caps: bool,
759 transform: Matrix4<f32>,
760 color: Color,
761 ) {
762 let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
763
764 let half_height = h / 2.0;
765
766 for i in 0..sides {
767 let nx0 = (d_phi * i as f32).cos();
768 let ny0 = (d_phi * i as f32).sin();
769 let nx1 = (d_phi * (i + 1) as f32).cos();
770 let ny1 = (d_phi * (i + 1) as f32).sin();
771
772 let x0 = r * nx0;
773 let z0 = r * ny0;
774 let x1 = r * nx1;
775 let z1 = r * ny1;
776
777 if caps {
778 self.draw_triangle(
780 transform
781 .transform_point(&Point3::new(x1, half_height, z1))
782 .coords,
783 transform
784 .transform_point(&Point3::new(x0, half_height, z0))
785 .coords,
786 transform
787 .transform_point(&Point3::new(0.0, half_height, 0.0))
788 .coords,
789 color,
790 );
791
792 self.draw_triangle(
794 transform
795 .transform_point(&Point3::new(x0, -half_height, z0))
796 .coords,
797 transform
798 .transform_point(&Point3::new(x1, -half_height, z1))
799 .coords,
800 transform
801 .transform_point(&Point3::new(0.0, -half_height, 0.0))
802 .coords,
803 color,
804 );
805 }
806
807 self.draw_triangle(
809 transform
810 .transform_point(&Point3::new(x0, -half_height, z0))
811 .coords,
812 transform
813 .transform_point(&Point3::new(x0, half_height, z0))
814 .coords,
815 transform
816 .transform_point(&Point3::new(x1, -half_height, z1))
817 .coords,
818 color,
819 );
820
821 self.draw_triangle(
822 transform
823 .transform_point(&Point3::new(x1, -half_height, z1))
824 .coords,
825 transform
826 .transform_point(&Point3::new(x0, half_height, z0))
827 .coords,
828 transform
829 .transform_point(&Point3::new(x1, half_height, z1))
830 .coords,
831 color,
832 );
833 }
834 }
835
836 pub fn draw_flat_capsule(
838 &mut self,
839 radius: f32,
840 height: f32,
841 segments: usize,
842 transform: Matrix4<f32>,
843 color: Color,
844 ) {
845 self.draw_circle_segment(
846 Vector3::new(0.0, height * 0.5, 0.0),
847 radius,
848 segments,
849 0.0,
850 std::f32::consts::PI,
851 transform,
852 color,
853 );
854
855 self.draw_circle_segment(
856 Vector3::new(0.0, -height * 0.5, 0.0),
857 radius,
858 segments,
859 std::f32::consts::PI,
860 std::f32::consts::TAU,
861 transform,
862 color,
863 );
864
865 self.add_line(Line {
866 begin: transform
867 .transform_point(&Point3::new(-radius, height * 0.5, 0.0))
868 .coords,
869 end: transform
870 .transform_point(&Point3::new(-radius, -height * 0.5, 0.0))
871 .coords,
872 color,
873 });
874 self.add_line(Line {
875 begin: transform
876 .transform_point(&Point3::new(radius, height * 0.5, 0.0))
877 .coords,
878 end: transform
879 .transform_point(&Point3::new(radius, -height * 0.5, 0.0))
880 .coords,
881 color,
882 });
883 }
884
885 pub fn draw_capsule(
887 &mut self,
888 radius: f32,
889 height: f32,
890 transform: Matrix4<f32>,
891 color: Color,
892 ) {
893 self.draw_sphere_section(
895 radius,
896 0.0..std::f32::consts::FRAC_PI_2,
897 10,
898 0.0..std::f32::consts::TAU,
899 10,
900 transform * Matrix4::new_translation(&Vector3::new(0.0, height * 0.5 - radius, 0.0)),
901 color,
902 );
903
904 self.draw_sphere_section(
906 radius,
907 std::f32::consts::PI..std::f32::consts::PI * 1.5,
908 10,
909 0.0..std::f32::consts::TAU,
910 10,
911 transform * Matrix4::new_translation(&Vector3::new(0.0, -height * 0.5 + radius, 0.0)),
912 color,
913 );
914
915 let cylinder_height = height - 2.0 * radius;
916
917 if cylinder_height > 0.0 {
918 self.draw_cylinder(10, radius, cylinder_height, false, transform, color);
919 }
920 }
921
922 pub fn draw_segment_flat_capsule(
925 &mut self,
926 begin: Vector2<f32>,
927 end: Vector2<f32>,
928 radius: f32,
929 segments: usize,
930 transform: Matrix4<f32>,
931 color: Color,
932 ) {
933 self.draw_circle(
936 Vector3::new(begin.x, begin.y, 0.0),
937 radius,
938 segments,
939 transform,
940 color,
941 );
942 self.draw_circle(
943 Vector3::new(end.x, end.y, 0.0),
944 radius,
945 segments,
946 transform,
947 color,
948 );
949 let perp = (end - begin)
950 .try_normalize(f32::EPSILON)
951 .map(|v| Vector2::new(v.y, -v.x).scale(radius))
952 .unwrap_or_default();
953
954 self.add_line(Line {
955 begin: transform
956 .transform_point(&Point3::from((begin - perp).to_homogeneous()))
957 .coords,
958 end: transform
959 .transform_point(&Point3::from((end - perp).to_homogeneous()))
960 .coords,
961 color,
962 });
963 self.add_line(Line {
964 begin: transform
965 .transform_point(&Point3::from((begin + perp).to_homogeneous()))
966 .coords,
967 end: transform
968 .transform_point(&Point3::from((end + perp).to_homogeneous()))
969 .coords,
970 color,
971 });
972 }
973
974 pub fn draw_segment_capsule(
976 &mut self,
977 begin: Vector3<f32>,
978 end: Vector3<f32>,
979 radius: f32,
980 v_segments: usize,
981 h_segments: usize,
982 transform: Matrix4<f32>,
983 color: Color,
984 ) {
985 let axis = end - begin;
986 let length = axis.norm();
987
988 let z_axis = axis.try_normalize(f32::EPSILON).unwrap_or_else(Vector3::z);
989
990 let y_axis = z_axis
991 .cross(
992 &(if z_axis.y != 0.0 || z_axis.z != 0.0 {
993 Vector3::x()
994 } else {
995 Vector3::y()
996 }),
997 )
998 .try_normalize(f32::EPSILON)
999 .unwrap_or_else(Vector3::y);
1000
1001 let x_axis = z_axis
1002 .cross(&y_axis)
1003 .try_normalize(f32::EPSILON)
1004 .unwrap_or_else(Vector3::x); let shaft_point = |u: f32, v: f32| -> Vector3<f32> {
1007 transform
1008 .transform_point(&Point3::from(
1009 begin
1010 + x_axis.scale((std::f32::consts::TAU * u).cos() * radius)
1011 + y_axis.scale((std::f32::consts::TAU * u).sin() * radius)
1012 + z_axis.scale(v * length),
1013 ))
1014 .coords
1015 };
1016
1017 let start_hemisphere_point = |u: f32, v: f32| -> Vector3<f32> {
1018 let latitude = std::f32::consts::FRAC_PI_2 * (v - 1.0);
1019 transform
1020 .transform_point(&Point3::from(
1021 begin
1022 + x_axis.scale((std::f32::consts::TAU * u).cos() * latitude.cos() * radius)
1023 + y_axis.scale((std::f32::consts::TAU * u).sin() * latitude.cos() * radius)
1024 + z_axis.scale(latitude.sin() * radius),
1025 ))
1026 .coords
1027 };
1028
1029 let end_hemisphere_point = |u: f32, v: f32| -> Vector3<f32> {
1030 let latitude = std::f32::consts::FRAC_PI_2 * v;
1031 transform
1032 .transform_point(&Point3::from(
1033 end + x_axis.scale((std::f32::consts::TAU * u).cos() * latitude.cos() * radius)
1034 + y_axis.scale((std::f32::consts::TAU * u).sin() * latitude.cos() * radius)
1035 + z_axis.scale(latitude.sin() * radius),
1036 ))
1037 .coords
1038 };
1039
1040 let dv = 1.0 / h_segments as f32;
1041 let du = 1.0 / v_segments as f32;
1042
1043 let mut u = 0.0;
1044 while u < 1.0 {
1045 let sa = shaft_point(u, 0.0);
1046 let sb = shaft_point(u, 1.0);
1047 let sc = shaft_point(u + du, 1.0);
1048 let sd = shaft_point(u + du, 0.0);
1049
1050 self.draw_triangle(sa, sb, sc, color);
1051 self.draw_triangle(sa, sc, sd, color);
1052
1053 u += du;
1054 }
1055
1056 u = 0.0;
1057 while u < 1.0 {
1058 let mut v = 0.0;
1059 while v < 1.0 {
1060 let sa = start_hemisphere_point(u, v);
1061 let sb = start_hemisphere_point(u, v + dv);
1062 let sc = start_hemisphere_point(u + du, v + dv);
1063 let sd = start_hemisphere_point(u + du, v);
1064
1065 self.draw_triangle(sa, sb, sc, color);
1066 self.draw_triangle(sa, sc, sd, color);
1067
1068 let ea = end_hemisphere_point(u, v);
1069 let eb = end_hemisphere_point(u, v + dv);
1070 let ec = end_hemisphere_point(u + du, v + dv);
1071 let ed = end_hemisphere_point(u + du, v);
1072
1073 self.draw_triangle(ea, eb, ec, color);
1074 self.draw_triangle(ea, ec, ed, color);
1075
1076 v += dv;
1077 }
1078
1079 u += du;
1080 }
1081 }
1082
1083 pub fn draw_arrow(
1085 &mut self,
1086 sides: usize,
1087 color: Color,
1088 length: f32,
1089 radius: f32,
1090 transform: Matrix4<f32>,
1091 ) {
1092 self.draw_cylinder(sides, radius, length, true, transform, color);
1093
1094 let head_radius = radius * 2.0;
1095 let head_height = radius * 4.0;
1096
1097 self.draw_cone(
1098 sides,
1099 head_radius,
1100 head_height,
1101 transform
1102 * Matrix4::new_translation(&Vector3::new(0.0, (length + head_height) * 0.5, 0.0)),
1103 color,
1104 true,
1105 );
1106 }
1107
1108 pub fn add_line(&mut self, line: Line) {
1110 self.lines.push(line);
1111 }
1112
1113 pub fn clear_lines(&mut self) {
1116 self.lines.clear()
1117 }
1118}