43 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] |
43 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] |
44 pub struct CapPoint { |
44 pub struct CapPoint { |
45 pub r : f64, |
45 pub r : f64, |
46 pub angle : Angle |
46 pub angle : Angle |
47 } |
47 } |
48 |
|
49 /// Rotate input vector by angle φ. |
|
50 #[inline] |
|
51 fn rotate(φ : f64, Loc([x, y]) : Loc<f64, 2>) -> Loc<f64, 2> { |
|
52 let sin_φ = φ.sin(); |
|
53 let cos_φ = φ.cos(); |
|
54 [cos_φ * x - sin_φ * y, sin_φ * x + cos_φ * y].into() |
|
55 } |
|
56 |
|
57 /// Mirror y coordinate of input vector. |
|
58 #[inline] |
|
59 fn ymirror(Loc([x, y]) : Loc<f64, 2>) -> Loc<f64, 2> { |
|
60 [x, -y].into() |
|
61 } |
|
62 |
|
63 |
48 |
64 impl CapPoint { |
49 impl CapPoint { |
65 #[inline] |
50 #[inline] |
66 /// Convert to cylindrical coordinates given z coordinate |
51 /// Convert to cylindrical coordinates given z coordinate |
67 fn cyl_coords(&self, z : f64) -> CylCoords { |
52 fn cyl_coords(&self, z : f64) -> CylCoords { |
117 /// Convert tangent from side tangent to cap tangent |
102 /// Convert tangent from side tangent to cap tangent |
118 fn tangent_from_side(&self, top : bool, t : Tangent) -> Tangent { |
103 fn tangent_from_side(&self, top : bool, t : Tangent) -> Tangent { |
119 if top { |
104 if top { |
120 // The angle is such that down would be rotated to self.angle, counterclockwise |
105 // The angle is such that down would be rotated to self.angle, counterclockwise |
121 // The new tangent is R[down + t] - R[down] = Rt. |
106 // The new tangent is R[down + t] - R[down] = Rt. |
122 rotate(self.angle+f64::PI/2.0, t) |
107 t.rotate(self.angle+f64::PI/2.0) |
123 } else { |
108 } else { |
124 // The angle is such that up would be rotated to self.angle, clockwise |
109 // The angle is such that up would be rotated to self.angle, clockwise |
125 rotate(self.angle+f64::PI/2.0, ymirror(t)) |
110 t.reflect_y().rotate(self.angle+f64::PI/2.0) |
126 } |
111 } |
127 } |
112 } |
128 |
113 |
129 #[inline] |
114 #[inline] |
130 /// Convert tangent from cap tangent to tangent tangent |
115 /// Convert tangent from cap tangent to tangent tangent |
131 fn tangent_to_side(&self, top : bool, t : Tangent) -> Tangent { |
116 fn tangent_to_side(&self, top : bool, t : Tangent) -> Tangent { |
132 if top { |
117 if top { |
133 // The angle is such that self.angle would be rotated to down, clockwise |
118 // The angle is such that self.angle would be rotated to down, clockwise |
134 rotate(-self.angle-f64::PI/2.0, t) |
119 t.rotate(-self.angle-f64::PI/2.0) |
135 } else { |
120 } else { |
136 // The angle is such that self.angle would be rotated to up, counterclockwise |
121 // The angle is such that self.angle would be rotated to up, counterclockwise |
137 ymirror(rotate(-self.angle-f64::PI/2.0, t)) |
122 t.rotate(-self.angle-f64::PI/2.0).reflect_y() |
138 } |
123 } |
139 } |
124 } |
140 } |
125 } |
141 |
126 |
142 /// Coordinates on a side |
127 /// Coordinates on a side |
979 let angles = [0.0, π/2.0, π*5.0/6.0, π*7.0/5.0]; |
964 let angles = [0.0, π/2.0, π*5.0/6.0, π*7.0/5.0]; |
980 |
965 |
981 for φ in angles { |
966 for φ in angles { |
982 let p = CYL.on_top(φ, CYL.radius / 2.0); |
967 let p = CYL.on_top(φ, CYL.radius / 2.0); |
983 let q_target = CYL.on_side(φ, CYL.height / 2.0); |
968 let q_target = CYL.on_side(φ, CYL.height / 2.0); |
984 let t = rotate(φ, [CYL.radius, 0.0].into()); |
969 let t = Loc([CYL.radius, 0.0]).rotate(φ); |
985 let t_target = Loc([0.0, -CYL.radius / 2.0]); |
970 let t_target = Loc([0.0, -CYL.radius / 2.0]); |
986 let (q, t_left) = CYL.partial_exp(p.point, t); |
971 let (q, t_left) = CYL.partial_exp(p.point, t); |
987 check_point_eq!(q, q_target.point); |
972 check_point_eq!(q, q_target.point); |
988 if let Some(t_left_) = t_left { |
973 if let Some(t_left_) = t_left { |
989 check_vec_eq!(t_left_, t_target); |
974 check_vec_eq!(t_left_, t_target); |
993 } |
978 } |
994 |
979 |
995 for φ in angles { |
980 for φ in angles { |
996 let p = CYL.on_top(φ + π/2.0, CYL.radius); |
981 let p = CYL.on_top(φ + π/2.0, CYL.radius); |
997 let q_target = CYL.on_side(φ, CYL.height / 2.0); |
982 let q_target = CYL.on_side(φ, CYL.height / 2.0); |
998 let t = 2.0 * rotate(φ, Loc([CYL.radius, -CYL.radius])); |
983 let t = 2.0 * Loc([CYL.radius, -CYL.radius]).rotate(φ); |
999 let t_target = Loc([-CYL.radius, -CYL.radius]); |
984 let t_target = Loc([-CYL.radius, -CYL.radius]); |
1000 let (q, t_left) = CYL.partial_exp(p.point, t); |
985 let (q, t_left) = CYL.partial_exp(p.point, t); |
1001 check_point_eq!(q, q_target.point); |
986 check_point_eq!(q, q_target.point); |
1002 if let Some(t_left_) = t_left { |
987 if let Some(t_left_) = t_left { |
1003 check_vec_eq!(t_left_, t_target); |
988 check_vec_eq!(t_left_, t_target); |
1012 let π = f64::PI; |
997 let π = f64::PI; |
1013 let angles = [0.0, π/2.0, π*5.0/6.0, π*7.0/5.0]; |
998 let angles = [0.0, π/2.0, π*5.0/6.0, π*7.0/5.0]; |
1014 |
999 |
1015 for φ in angles { |
1000 for φ in angles { |
1016 let pt = CYL.on_top(φ, CYL.radius); |
1001 let pt = CYL.on_top(φ, CYL.radius); |
1017 let t = rotate(φ, Loc([0.1, 0.3])); |
1002 let t = Loc([0.1, 0.3]).rotate(φ); |
1018 let b = pt.clone().exp(&t); |
1003 let b = pt.clone().exp(&t); |
1019 let a = pt.exp(&(-t)); |
1004 let a = pt.exp(&(-t)); |
1020 check_point_eq!(a.exp(&(2.0*t)).point, b.point); |
1005 check_point_eq!(a.exp(&(2.0*t)).point, b.point); |
1021 } |
1006 } |
1022 } |
1007 } |