Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

1use bone_types::{ 2 Aabb3, AngleTolerance, ChordHeightTolerance, Length, Parameter, Plane3, Point3, Tolerance, 3 UnitVec3, Vec3, 4}; 5use uom::si::length::millimeter; 6 7use crate::KernelError; 8use crate::circular3; 9use crate::mesh::{MeshVertex, TriMesh}; 10use crate::surface3::Surface3; 11 12#[derive(Copy, Clone, Debug, PartialEq)] 13pub struct PlaneSurface { 14 plane: Plane3, 15 u_extent: Length, 16 v_extent: Length, 17} 18 19impl PlaneSurface { 20 pub fn new( 21 plane: Plane3, 22 u_extent: Length, 23 v_extent: Length, 24 tolerance: Tolerance, 25 ) -> Result<Self, KernelError> { 26 let u = u_extent.get::<millimeter>(); 27 let v = v_extent.get::<millimeter>(); 28 if !u.is_finite() || !v.is_finite() || u < tolerance.value() || v < tolerance.value() { 29 return Err(KernelError::DegeneratePlane); 30 } 31 Ok(Self { 32 plane, 33 u_extent, 34 v_extent, 35 }) 36 } 37 38 #[must_use] 39 pub const fn plane(self) -> Plane3 { 40 self.plane 41 } 42 43 #[must_use] 44 pub const fn u_extent(self) -> Length { 45 self.u_extent 46 } 47 48 #[must_use] 49 pub const fn v_extent(self) -> Length { 50 self.v_extent 51 } 52 53 #[must_use] 54 fn point_at(self, u: f64, v: f64) -> Point3 { 55 let (ox, oy, oz) = self.plane.origin().coords_mm(); 56 let (xx, xy, xz) = self.plane.x_axis().components(); 57 let (yx, yy, yz) = self.plane.y_axis().components(); 58 let su = u * self.u_extent.get::<millimeter>(); 59 let sv = v * self.v_extent.get::<millimeter>(); 60 Point3::from_mm( 61 ox + su * xx + sv * yx, 62 oy + su * xy + sv * yy, 63 oz + su * xz + sv * yz, 64 ) 65 } 66} 67 68impl Surface3 for PlaneSurface { 69 fn evaluate(&self, u: Parameter, v: Parameter) -> Point3 { 70 self.point_at(u.value(), v.value()) 71 } 72 73 fn partials(&self, _u: Parameter, _v: Parameter) -> (Vec3, Vec3) { 74 ( 75 self.plane.x_axis().into_vec(self.u_extent), 76 self.plane.y_axis().into_vec(self.v_extent), 77 ) 78 } 79 80 fn normal(&self, _u: Parameter, _v: Parameter) -> UnitVec3 { 81 self.plane.normal() 82 } 83 84 fn bounding_box(&self) -> Aabb3 { 85 Aabb3::from_corners(self.point_at(0.0, 0.0), self.point_at(1.0, 1.0)).union( 86 Aabb3::from_corners(self.point_at(1.0, 0.0), self.point_at(0.0, 1.0)), 87 ) 88 } 89 90 fn contains_point(&self, p: Point3, tolerance: Tolerance) -> bool { 91 let (a, b, off_plane) = circular3::local_coords(self.plane, p); 92 if off_plane.abs() > tolerance.value() { 93 return false; 94 } 95 let tol = tolerance.value(); 96 (-tol..=self.u_extent.get::<millimeter>() + tol).contains(&a) 97 && (-tol..=self.v_extent.get::<millimeter>() + tol).contains(&b) 98 } 99 100 fn tessellate(&self, _chord: ChordHeightTolerance, _angle: AngleTolerance) -> TriMesh { 101 let normal = self.plane.normal(); 102 TriMesh::from_grid(2, 2, |i, j| { 103 MeshVertex::new(self.point_at(f64::from(i), f64::from(j)), normal) 104 }) 105 } 106} 107 108impl core::fmt::Display for PlaneSurface { 109 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 110 write!( 111 f, 112 "plane_surface{{ o={}, normal={}, u={} mm, v={} mm }}", 113 self.plane.origin(), 114 self.plane.normal(), 115 self.u_extent.get::<millimeter>(), 116 self.v_extent.get::<millimeter>(), 117 ) 118 } 119}