1use std::convert::TryFrom;
4use derive_more::From;
5use num_traits as num;
6#[cfg(feature = "derive_serdes")]
7use serde::{Deserialize, Serialize};
8
9use crate::*;
10
11use super::{Aabb3, Capsule3, Cylinder3, Sphere3};
12
13pub trait Shape <S : Ring> : Aabb <S> { } pub trait Aabb <S : Ring> : Stereometric <S> {
35 fn aabb (&self) -> Aabb3 <S>;
36}
37
38pub trait Bsphere <S : Ring> : Stereometric <S> {
41 fn sphere (&self) -> Sphere3 <S>;
42}
43
44pub trait Stereometric <S : Ring> {
48 fn volume (&self) -> Positive <S>;
49}
50
51#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
58#[derive(From, Clone, Debug, PartialEq)]
59pub enum Variant <S> {
60 Bounded (Bounded <S>),
61 Unbounded (Unbounded <S>)
62}
63
64#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
66#[derive(From, Clone, Debug, PartialEq)]
67pub enum Bounded <S> {
68 Sphere (Sphere <S>),
69 Capsule (Capsule <S>),
70 Cylinder (Cylinder <S>),
71 Cone (Cone <S>),
72 Cube (Cube <S>),
73 Cuboid (Cuboid <S>)
74}
75
76#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
78#[derive(From, Clone, Debug, PartialEq)]
79pub enum Unbounded <S> {
80 Orthant (Orthant),
81 Halfspace (Halfspace <S>)
82}
83
84#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
90#[derive(Clone, Copy, Debug, PartialEq)]
91pub struct Orthant {
92 pub normal_axis : SignedAxis3
93}
94
95#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
97#[derive(Clone, Copy, Debug, PartialEq)]
98pub struct Halfspace <S> {
99 pub normal_vector : Unit3 <S>
100}
101
102#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
104#[derive(Clone, Copy, Debug, PartialEq)]
105pub struct Sphere <S> {
106 pub radius : Positive <S>
107}
108
109#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
111#[derive(Clone, Copy, Debug, PartialEq)]
112pub struct Capsule <S> {
113 pub radius : Positive <S>,
114 pub half_height : Positive <S>
115}
116
117#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
119#[derive(Clone, Copy, Debug, PartialEq)]
120pub struct Cylinder <S> {
121 pub radius : Positive <S>,
122 pub half_height : Positive <S>
123}
124
125#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
127#[derive(Clone, Copy, Debug, PartialEq)]
128pub struct Cone <S> {
129 pub radius : Positive <S>,
130 pub half_height : Positive <S>
131}
132
133#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
135#[derive(Clone, Copy, Debug, PartialEq)]
136pub struct Cube <S> {
137 pub half_extent : Positive <S>
138}
139
140#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
142#[derive(Clone, Copy, Debug, PartialEq)]
143pub struct Cuboid <S> {
144 pub half_extent_x : Positive <S>,
145 pub half_extent_y : Positive <S>,
146 pub half_extent_z : Positive <S>
147}
148
149impl <S> Halfspace <S> {
154 #[inline]
155 pub fn numcast <T> (self) -> Option <Halfspace <T>> where
156 S : num::NumCast,
157 T : num::NumCast
158 {
159 Some (Halfspace {
160 normal_vector: self.normal_vector.numcast()?
161 })
162 }
163}
164
165impl <S> Sphere <S> {
166 #[inline]
167 pub fn numcast <T> (self) -> Option <Sphere <T>> where
168 S : num::NumCast,
169 T : num::NumCast
170 {
171 Some (Sphere {
172 radius: self.radius.numcast()?
173 })
174 }
175}
176
177impl <S> Capsule <S> {
178 #[inline]
179 pub fn numcast <T> (self) -> Option <Capsule <T>> where
180 S : num::NumCast,
181 T : num::NumCast
182 {
183 Some (Capsule {
184 radius: self.radius.numcast()?,
185 half_height: self.half_height.numcast()?
186 })
187 }
188}
189
190impl <S> Cylinder <S> {
191 #[inline]
192 pub fn numcast <T> (self) -> Option <Cylinder <T>> where
193 S : num::NumCast,
194 T : num::NumCast
195 {
196 Some (Cylinder {
197 radius: self.radius.numcast()?,
198 half_height: self.half_height.numcast()?
199 })
200 }
201}
202
203impl <S> Cone <S> {
204 #[inline]
205 pub fn numcast <T> (self) -> Option <Cone <T>> where
206 S : num::NumCast,
207 T : num::NumCast
208 {
209 Some (Cone {
210 radius: self.radius.numcast()?,
211 half_height: self.half_height.numcast()?
212 })
213 }
214}
215
216impl <S> Cube <S> {
217 #[inline]
218 pub fn numcast <T> (self) -> Option <Cube <T>> where
219 S : num::NumCast,
220 T : num::NumCast
221 {
222 Some (Cube {
223 half_extent: self.half_extent.numcast()?
224 })
225 }
226}
227
228impl <S> Cuboid <S> {
229 #[inline]
230 pub fn numcast <T> (self) -> Option <Cuboid <T>> where
231 S : num::NumCast,
232 T : num::NumCast
233 {
234 Some (Cuboid {
235 half_extent_x: self.half_extent_x.numcast()?,
236 half_extent_y: self.half_extent_y.numcast()?,
237 half_extent_z: self.half_extent_z.numcast()?
238 })
239 }
240}
241
242pub fn report_sizes() {
247 use std::mem::size_of;
248 println!("shape report sizes...");
249
250 macro_rules! show {
251 ($e:expr) => { println!("{}: {:?}", stringify!($e), $e); }
252 }
253
254 show!(size_of::<Variant <f32>>());
255 show!(size_of::<Variant <f64>>());
256
257 show!(size_of::<Bounded <f32>>());
258 show!(size_of::<Bounded <f64>>());
259
260 show!(size_of::<Unbounded <f32>>());
261 show!(size_of::<Unbounded <f64>>());
262
263 show!(size_of::<Sphere <f32>>());
264 show!(size_of::<Capsule <f32>>());
265 show!(size_of::<Cylinder <f32>>());
266 show!(size_of::<Cone <f32>>());
267 show!(size_of::<Cube <f32>>());
268 show!(size_of::<Cuboid <f32>>());
269
270 show!(size_of::<Orthant>());
271 show!(size_of::<Halfspace <f32>>());
272
273 show!(size_of::<Sphere <f64>>());
274 show!(size_of::<Capsule <f64>>());
275 show!(size_of::<Cylinder <f64>>());
276 show!(size_of::<Cone <f64>>());
277 show!(size_of::<Cube <f64>>());
278 show!(size_of::<Cuboid <f64>>());
279
280 show!(size_of::<Orthant>());
281 show!(size_of::<Halfspace <f64>>());
282
283 println!("...shape report sizes");
284}
285
286impl <S> Shape <S> for Variant <S> where
294 S : Real + num::float::FloatCore + std::fmt::Debug
295{ }
296impl <S> Aabb <S> for Variant <S> where
297 S : Real + num::float::FloatCore + std::fmt::Debug
298{
299 fn aabb (&self) -> Aabb3 <S> {
302 match self {
303 Variant::Bounded (bounded) => bounded.aabb(),
304 Variant::Unbounded (unbounded) => unbounded.aabb()
305 }
306 }
307}
308impl <S> Stereometric <S> for Variant <S> where
309 S : Real + num::float::FloatCore + std::fmt::Debug
310{
311 fn volume (&self) -> Positive <S> {
314 match self {
315 Variant::Bounded (bounded) => bounded.volume(),
316 Variant::Unbounded (unbounded) => unbounded.volume()
317 }
318 }
319}
320
321impl <S> TryFrom <Variant <S>> for Bounded <S> where S : Real + std::fmt::Debug {
325 type Error = Variant <S>;
326 fn try_from (variant : Variant <S>) -> Result <Self, Self::Error> {
327 match variant {
328 Variant::Bounded (bounded) => Ok (bounded),
329 _ => Err (variant)
330 }
331 }
332}
333impl <S> Shape <S> for Bounded <S> where S : Real + std::fmt::Debug { }
334impl <S> Aabb <S> for Bounded <S> where S : Real + std::fmt::Debug {
335 fn aabb (&self) -> Aabb3 <S> {
336 match self {
337 Bounded::Sphere (sphere) => sphere.aabb(),
338 Bounded::Capsule (capsule) => capsule.aabb(),
339 Bounded::Cylinder (cylinder) => cylinder.aabb(),
340 Bounded::Cone (cone) => cone.aabb(),
341 Bounded::Cube (cube) => cube.aabb(),
342 Bounded::Cuboid (cuboid) => cuboid.aabb()
343 }
344 }
345}
346impl <S : Real> Stereometric <S> for Bounded <S> {
347 fn volume (&self) -> Positive <S> {
349 match self {
350 Bounded::Sphere (sphere) => sphere.volume(),
351 Bounded::Capsule (capsule) => capsule.volume(),
352 Bounded::Cylinder (cylinder) => cylinder.volume(),
353 Bounded::Cone (cone) => cone.volume(),
354 Bounded::Cube (cube) => cube.volume(),
355 Bounded::Cuboid (cuboid) => cuboid.volume()
356 }
357 }
358}
359
360impl <S : Real> TryFrom <Variant <S>> for Unbounded <S> {
364 type Error = Variant <S>;
365 fn try_from (variant : Variant <S>) -> Result <Self, Self::Error> {
366 match variant {
367 Variant::Unbounded (unbounded) => Ok (unbounded),
368 _ => Err (variant)
369 }
370 }
371}
372impl <S> Shape <S> for Unbounded <S> where
373 S : Real + num::float::FloatCore + std::fmt::Debug
374{ }
375impl <S> Aabb <S> for Unbounded <S> where
376 S : Real + num::float::FloatCore + std::fmt::Debug
377{
378 fn aabb (&self) -> Aabb3 <S> {
379 match self {
380 Unbounded::Orthant (orthant) => orthant.aabb(),
381 Unbounded::Halfspace (halfspace) => halfspace.aabb()
382 }
383 }
384}
385impl <S> Stereometric <S> for Unbounded <S> where
386 S : Real + num::float::FloatCore + std::fmt::Debug
387{
388 fn volume (&self) -> Positive <S> {
390 if cfg!(debug_assertions) {
391 let volume = match self {
392 Unbounded::Orthant (orthant) => orthant.volume(),
393 Unbounded::Halfspace (halfspace) => halfspace.volume()
394 };
395 debug_assert_eq!(*volume, S::infinity());
396 }
397 Positive::infinity()
398 }
399}
400
401impl <S : Ring> Sphere <S> {
405 #[inline]
406 pub fn unit() -> Self where S : Field {
408 use num::One;
409 Sphere { radius: Positive::one() }
410 }
411 #[inline]
420 pub fn noisy (radius : S) -> Self where S : std::fmt::Debug {
421 assert_ne!(radius, S::zero());
422 Sphere { radius: Positive::unchecked (radius.abs()) }
423 }
424 #[inline]
433 pub fn unchecked (radius : S) -> Self where S : std::fmt::Debug {
434 debug_assert_ne!(radius, S::zero());
435 Sphere { radius: Positive::unchecked (radius.abs()) }
436 }
437 #[inline]
438 pub fn sphere3 (&self, center : Point3 <S>) -> Sphere3 <S> {
439 Sphere3 { center, radius: self.radius }
440 }
441}
442impl <S : Real> TryFrom <Bounded <S>> for Sphere <S> {
443 type Error = Bounded <S>;
444 fn try_from (bounded : Bounded <S>) -> Result <Self, Self::Error> {
445 match bounded {
446 Bounded::Sphere (sphere) => Ok (sphere),
447 _ => Err (bounded)
448 }
449 }
450}
451impl <S> Shape <S> for Sphere <S> where S : Real + std::fmt::Debug { }
452impl <S> Aabb <S> for Sphere <S> where S : Real + std::fmt::Debug {
453 fn aabb (&self) -> Aabb3 <S> {
454 Aabb3::with_minmax ([-*self.radius; 3].into(), [ *self.radius; 3].into())
455 }
456}
457impl <S : Real> Stereometric <S> for Sphere <S> {
458 fn volume (&self) -> Positive <S> {
459 let four = Positive::unchecked (S::four());
460 let frac_pi_3 = Positive::unchecked (S::frac_pi_3());
461 four * frac_pi_3 * self.radius * self.radius * self.radius
462 }
463}
464
465impl <S : Ring> Capsule <S> {
469 #[inline]
486 pub fn noisy (radius : S, half_height : S) -> Self where S : std::fmt::Debug {
487 assert_ne!(radius, S::zero());
488 assert_ne!(half_height, S::zero());
489 let radius = Positive::unchecked (radius.abs());
490 let half_height = Positive::unchecked (half_height.abs());
491 Capsule { radius, half_height }
492 }
493 #[inline]
510 pub fn unchecked (radius : S, half_height : S) -> Self where
511 S : std::fmt::Debug
512 {
513 debug_assert_ne!(radius, S::zero());
514 let radius = Positive::unchecked (radius.abs());
515 let half_height = Positive::unchecked (half_height.abs());
516 Capsule { radius, half_height }
517 }
518 #[inline]
520 pub fn height (&self) -> NonNegative <S> where S : Field {
521 self.half_height * NonNegative::unchecked (S::two())
522 }
523 #[inline]
524 pub fn capsule3 (&self, center : Point3 <S>) -> Capsule3 <S> {
525 Capsule3 { center, radius: self.radius, half_height: self.half_height }
526 }
527}
528impl <S> Shape <S> for Capsule <S> where S : Real + std::fmt::Debug { }
529impl <S> Aabb <S> for Capsule <S> where S : Real + std::fmt::Debug {
530 fn aabb (&self) -> Aabb3 <S> {
531 let r = *self.radius;
532 let hh = *self.half_height;
533 Aabb3::with_minmax ([-r, -r, -r - hh].into(), [ r, r, r + hh].into())
534 }
535}
536impl <S : Real> Stereometric <S> for Capsule <S> {
537 fn volume (&self) -> Positive <S> {
538 let r = self.radius;
539 let h = self.height();
540 let r2 = r * r;
541 let r3 = r2 * r;
542 let pi = Positive::unchecked (S::pi());
543 let four = Positive::unchecked (S::four());
544 let frac_pi_3 = Positive::unchecked (S::frac_pi_3());
545 let cylinder_volume = pi * r2 * h;
546 let sphere_volume = four * frac_pi_3 * r3;
547 sphere_volume + cylinder_volume
548 }
549}
550
551impl <S : Ring> Cylinder <S> {
555 #[inline]
556 pub fn unit() -> Self where S : Field {
558 use num::One;
559 Cylinder {
560 radius: Positive::one(), half_height: Positive::one()
561 }
562 }
563 #[inline]
573 pub fn noisy (radius : S, half_height : S) -> Self where S : std::fmt::Debug {
574 assert_ne!(radius, S::zero());
575 assert_ne!(half_height, S::zero());
576 let radius = Positive::unchecked (radius.abs());
577 let half_height = Positive::unchecked (half_height.abs());
578 Cylinder { radius, half_height }
579 }
580 #[inline]
590 pub fn unchecked (radius : S, half_height : S) -> Self where
591 S : std::fmt::Debug
592 {
593 debug_assert_ne!(radius, S::zero());
594 debug_assert_ne!(half_height, S::zero());
595 let radius = Positive::unchecked (radius.abs());
596 let half_height = Positive::unchecked (half_height.abs());
597 Cylinder { radius, half_height }
598 }
599 #[inline]
600 pub fn cylinder3 (&self, center : Point3 <S>) -> Cylinder3 <S> {
601 Cylinder3 { center, radius: self.radius, half_height: self.half_height }
602 }
603 #[inline]
604 pub fn height (&self) -> Positive <S> where S : Field {
605 self.half_height * Positive::unchecked (S::two())
606 }
607}
608impl <S> Shape <S> for Cylinder <S> where S : Real + std::fmt::Debug { }
609impl <S> Aabb <S> for Cylinder <S> where S : Real + std::fmt::Debug {
610 fn aabb (&self) -> Aabb3 <S> {
611 let r = *self.radius;
612 let hh = *self.half_height;
613 Aabb3::with_minmax ([-r, -r, -hh].into(), [ r, r, hh].into())
614 }
615}
616impl <S : Real> Stereometric <S> for Cylinder <S> {
617 fn volume (&self) -> Positive <S> {
618 let pi = Positive::unchecked (S::pi());
619 pi * self.radius * self.radius * self.height()
620 }
621}
622
623impl <S : Ring> Cone <S> {
627 #[inline]
637 pub fn noisy (radius : S, half_height : S) -> Self where S : std::fmt::Debug {
638 assert_ne!(radius, S::zero());
639 assert_ne!(half_height, S::zero());
640 let radius = Positive::unchecked (radius.abs());
641 let half_height = Positive::unchecked (half_height.abs());
642 Cone { radius, half_height }
643 }
644}
645impl <S> Shape <S> for Cone <S> where S : Real + std::fmt::Debug { }
646impl <S> Aabb <S> for Cone <S> where S : Real + std::fmt::Debug {
647 fn aabb (&self) -> Aabb3 <S> {
648 let r = *self.radius;
649 let hh = *self.half_height;
650 Aabb3::with_minmax ([-r, -r, -hh].into(), [ r, r, hh].into())
651 }
652}
653impl <S : Real> Stereometric <S> for Cone <S> {
654 fn volume (&self) -> Positive <S> {
655 let frac_pi_3 = Positive::unchecked (S::frac_pi_3());
656 let two = Positive::unchecked (S::two());
657 frac_pi_3 * self.radius * self.radius * two * self.half_height
658 }
659}
660
661impl <S : Ring> Cube <S> {
665 #[inline]
674 pub fn noisy (half_extent : S) -> Self where S : std::fmt::Debug {
675 assert_ne!(half_extent, S::zero());
676 let half_extent = Positive::unchecked (half_extent.abs());
677 Cube { half_extent }
678 }
679 #[inline]
680 pub fn extent (&self) -> Positive <S> where S : Field {
681 self.half_extent * Positive::unchecked (S::two())
682 }
683}
684impl <S> Shape <S> for Cube <S> where S : Field + std::fmt::Debug { }
685impl <S> Aabb <S> for Cube <S> where S : Field + std::fmt::Debug {
686 fn aabb (&self) -> Aabb3 <S> {
687 Aabb3::with_minmax (
688 [-*self.half_extent; 3].into(),
689 [ *self.half_extent; 3].into())
690 }
691}
692impl <S : Field> Stereometric <S> for Cube <S> {
693 fn volume (&self) -> Positive <S> {
694 let extent = self.extent();
695 extent * extent * extent
696 }
697}
698
699impl <S : Ring> Cuboid <S> {
703 #[inline]
712 pub fn noisy (half_extents : [S; 3]) -> Self where S : std::fmt::Debug {
713 assert_ne!(half_extents[0], S::zero());
714 assert_ne!(half_extents[1], S::zero());
715 assert_ne!(half_extents[2], S::zero());
716 let half_extent_x = Positive::unchecked (half_extents[0].abs());
717 let half_extent_y = Positive::unchecked (half_extents[1].abs());
718 let half_extent_z = Positive::unchecked (half_extents[2].abs());
719 Cuboid { half_extent_x, half_extent_y, half_extent_z }
720 }
721 #[inline]
722 pub fn extents (&self) -> [Positive <S>; 3] where S : Field {
723 let two = Positive::unchecked (S::two());
724 [
725 self.half_extent_x * two,
726 self.half_extent_y * two,
727 self.half_extent_z * two
728 ]
729 }
730 #[inline]
731 pub fn half_extents_vec (&self) -> Vector3 <S> {
732 [ *self.half_extent_x,
733 *self.half_extent_y,
734 *self.half_extent_z
735 ].into()
736 }
737 #[inline]
738 pub fn max (&self) -> Point3 <S> {
739 Vector3 {
740 x: *self.half_extent_x,
741 y: *self.half_extent_y,
742 z: *self.half_extent_z
743 }.into()
744 }
745 #[inline]
746 pub fn min (&self) -> Point3 <S> {
747 Vector3 {
748 x: -*self.half_extent_x,
749 y: -*self.half_extent_y,
750 z: -*self.half_extent_z
751 }.into()
752 }
753 #[inline]
754 pub fn aabb3 (&self, center : Point3 <S>) -> Aabb3 <S> where
755 S : std::fmt::Debug
756 {
757 Aabb3::with_minmax (
758 center + self.min().0,
759 center + self.max().0
760 )
761 }
762}
763impl <S> From <Aabb3 <S>> for Cuboid <S> where S : Field {
764 fn from (aabb : Aabb3 <S>) -> Self {
765 Cuboid {
767 half_extent_x: Positive::unchecked (*aabb.width() / S::two()),
768 half_extent_y: Positive::unchecked (*aabb.depth() / S::two()),
769 half_extent_z: Positive::unchecked (*aabb.height() / S::two())
770 }
771 }
772}
773impl <S> Shape <S> for Cuboid <S> where S : Field + std::fmt::Debug { }
774impl <S> Aabb <S> for Cuboid <S> where S : Field + std::fmt::Debug {
775 fn aabb (&self) -> Aabb3 <S> {
776 Aabb3::with_minmax (self.min(), self.max())
777 }
778}
779impl <S : Field> Stereometric <S> for Cuboid <S> {
780 fn volume (&self) -> Positive <S> {
781 let [x, y, z] = self.extents();
782 x * y * z
783 }
784}
785
786impl Orthant {
790 pub fn try_from <S : Real> (halfspace : &Halfspace <S>) -> Option <Self> {
791 if let Some (normal_axis) = SignedAxis3::try_from (&halfspace.normal_vector) {
792 Some (Orthant { normal_axis })
793 } else {
794 None
795 }
796 }
797}
798impl From <SignedAxis3> for Orthant {
799 fn from (normal_axis : SignedAxis3) -> Self {
800 Orthant { normal_axis }
801 }
802}
803impl <S> Shape <S> for Orthant where
804 S : Field + num::float::FloatCore + std::fmt::Debug
805{ }
806impl <S> Aabb <S> for Orthant where
807 S : Field + num::float::FloatCore + std::fmt::Debug
808{
809 fn aabb (&self) -> Aabb3 <S> {
828 use num::float::FloatCore;
829 let axis_vec = self.normal_axis.to_vec::<S>();
830 let surface = Vector3::broadcast (S::one()) - axis_vec.map (FloatCore::abs);
831
832 let do_min = |i| if surface[i] == S::one() {
833 S::neg_infinity()
834 } else if axis_vec[i] == S::one() {
835 S::neg_infinity()
836 } else {
837 debug_assert_eq!(axis_vec[i], -S::one());
838 S::zero()
839 };
840 let do_max = |i| if surface[i] == S::one() {
841 S::infinity()
842 } else if axis_vec[i] == S::one() {
843 S::zero()
844 } else {
845 debug_assert_eq!(axis_vec[i], -S::one());
846 S::infinity()
847 };
848 let min = [ do_min (0), do_min (1), do_min (2) ].into();
849 let max = [ do_max (0), do_max (1), do_max (2) ].into();
850
851 Aabb3::with_minmax (min, max)
852 }
853}
854impl <S> Stereometric <S> for Orthant where S : Ring + num::float::FloatCore {
855 fn volume (&self) -> Positive <S> {
857 Positive::infinity()
858 }
859}
860
861impl <S : Real> From <Unit3 <S>> for Halfspace <S> {
865 fn from (normal_vector : Unit3 <S>) -> Self {
866 Halfspace { normal_vector }
867 }
868}
869impl <S> Shape <S> for Halfspace <S> where
870 S : Real + num::float::FloatCore + std::fmt::Debug
871{ }
872impl <S> Aabb <S> for Halfspace <S> where
873 S : Real + num::float::FloatCore + std::fmt::Debug
874{
875 fn aabb (&self) -> Aabb3 <S> {
876 if let Some (orthant) = Orthant::try_from (&self) {
877 orthant.aabb()
878 } else {
879 Aabb3::with_minmax (
880 [S::neg_infinity(); 3].into(),
881 [S::infinity(); 3].into())
882 }
883 }
884}
885impl <S> Stereometric <S> for Halfspace <S> where
886 S : Real + num::float::FloatCore
887{
888 fn volume (&self) -> Positive <S> {
890 Positive::infinity()
891 }
892}