f99963798b91dca637c70a59b0c42ec772e8cf4b
[nit.git] / lib / geometry / angles.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Angle related service using `Float` to represent an angle in radians
16 module angles
17
18 import points_and_lines
19
20 redef class Point[N]
21 # Arctangent function using the difference between `self` and `other` as trigonometric ratio
22 #
23 # Behave similarly to the toplevel `atan2` as it returns the angle in the appropriate quadrant.
24 #
25 # ~~~
26 # var p0 = new Point[Float](0.0, 0.0)
27 # var p1 = new Point[Float](1.0, 1.0)
28 # assert p0.atan2(p1).is_approx(0.25*pi, 0.0001)
29 # ~~~
30 fun atan2(other: Point[N]): Float
31 do
32 var dx = other.x.to_f - x.to_f
33 var dy = other.y.to_f - y.to_f
34 var a = sys.atan2(dy.to_f, dx.to_f)
35 return a
36 end
37 end
38
39 redef universal Float
40 # Normalize the `self` angle in radians to be within `[-pi .. pi[`
41 #
42 # ~~~
43 # assert (1.5*pi).angle_normalize.is_approx(-0.5*pi, 0.0001)
44 # assert 8.0.angle_normalize.is_approx(1.7168, 0.0001)
45 # assert (-1.0).angle_normalize == -1.0
46 # ~~~
47 fun angle_normalize: Float
48 do
49 var s = self
50 while s < -pi do s += 2.0*pi
51 while s >= pi do s -= 2.0*pi
52 return s
53 end
54
55 # Linear interpolation on the arc delimited by `self` and `other` at `p` out of 1.0
56 #
57 # The result is normalized with `angle_normalize`.
58 #
59 # ~~~
60 # assert 0.0.angle_lerp(pi, 0.5).is_approx(0.5*pi, 0.0001)
61 # assert 0.0.angle_lerp(pi, 8.5).is_approx(0.5*pi, 0.0001)
62 # assert 0.0.angle_lerp(pi, 7.5).is_approx(-0.5*pi, 0.0001)
63 # ~~~
64 fun angle_lerp(other, p: Float): Float
65 do
66 var d = other - self
67 var a = self + d*p
68 return a.angle_normalize
69 end
70 end