1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Interfaces and classes to represent basic geometry needs.
18 module points_and_lines
is serialize
22 # Abstract 2d point, strongly linked to its implementation `Point`
23 interface IPoint[N
: Numeric]
25 # Horizontal coordinate
31 redef fun to_s
do return "({x}, {y})"
33 # Distance with `other`
36 # var p0 = new Point[Float](0.0, 0.0)
37 # var p1 = new Point[Float](2.0, 3.0)
38 # assert p0.dist(p1).is_approx(3.6, 0.01)
41 # If `self` or `other` are in 3D, the distance takes into account the 3 axes.
42 # For a 2D point, the Z coordinate is considered to be 0.
45 # var p2 = new Point3d[Float](0.0, 0.0, 0.0)
46 # var p3 = new Point3d[Float](2.0, 3.0, 4.0)
47 # var p4 = new Point[Float](2.0, 3.0)
48 # assert p2.dist(p3).is_approx(5.385, 0.01)
49 # assert p2.dist(p4).is_approx(3.606, 0.01)
51 fun dist
(other
: Point[Numeric]): N
53 return x
.value_of
(dist2
(other
).to_f
.sqrt
)
56 # Square of the distance with `other`
58 # May be used as an approximation to compare distance between two points.
61 # var p0 = new Point[Float](0.0, 0.0)
62 # var p1 = new Point[Float](2.0, 3.0)
63 # assert p0.dist2(p1) == 13.0
66 # If `self` or `other` are in 3D, the distance takes into account the 3 axes.
67 # For a 2D point, the Z coordinate is considered to be 0.
70 # var p2 = new Point3d[Float](0.0, 0.0, 0.0)
71 # var p3 = new Point3d[Float](2.0, 3.0, 4.0)
72 # var p4 = new Point[Float](2.0, 3.0)
73 # assert p2.dist2(p3).is_approx(29.0, 0.01)
74 # assert p2.dist2(p4).is_approx(13.0, 0.01)
75 # assert p4.dist2(p2).is_approx(13.0, 0.01)
77 fun dist2
(other
: Point[Numeric]): N
78 do return x
.value_of
(other
.dist2_with_2d
(self))
80 private fun dist2_with_2d
(other
: IPoint[Numeric]): Numeric
81 do return dist2_xy
(other
)
83 private fun dist2_with_3d
(other
: IPoint3d[Numeric]): Numeric
84 do return dist2_xy
(other
).add
(other
.z
.mul
(other
.z
))
86 # Square of the distance with `other` on the X and Y axes
87 private fun dist2_xy
(other
: IPoint[N
]): N
89 var dx
= other
.x
.sub
(x
)
90 var dy
= other
.y
.sub
(y
)
91 var s
= (dx
.mul
(dx
)).add
(dy
.mul
(dy
))
95 # Linear interpolation between `self` and `other` at `p` out of `1.0`
98 # var p0 = new Point[Float](0.0, 0.0)
99 # var p1 = new Point[Float](2.0, 3.0)
100 # assert p0.lerp(p1, 0.0) == p0
101 # assert p0.lerp(p1, 1.0) == p1
102 # assert p0.lerp(p1, 0.5) == new Point[Float](1.0, 1.5)
105 # TODO 3D implementation.
106 fun lerp
(other
: Point[Numeric], p
: Float): Point[N
]
108 var xx
= x
.to_f
+ (other
.x
.to_f
- x
.to_f
).to_f
* p
109 var yy
= y
.to_f
+ (other
.y
.to_f
- y
.to_f
).to_f
* p
110 return new Point[N
](x
.value_of
(xx
), y
.value_of
(yy
))
113 redef fun ==(o
) do return o
isa IPoint[Numeric] and o
.x
== x
and o
.y
== y
116 # 2D point with `x` and `z`
117 class Point[N
: Numeric]
120 redef var x
: N
= 0.0 is writable, optional
121 redef var y
: N
= 0.0 is writable, optional
124 # Abstract 3d point, strongly linked to its implementation `Point3d`
125 interface IPoint3d[N
: Numeric]
131 redef fun to_s
do return "({x}, {y}, {z})"
133 redef fun dist2
(other
)
134 do return x
.value_of
(other
.dist2_with_3d
(self))
136 redef fun dist2_with_2d
(other
)
137 do return dist2_xy
(other
).add
(z
.mul
(z
))
139 redef fun dist2_with_3d
(other
)
141 var dz
= other
.z
.sub
(z
)
142 var s
= dist2_xy
(other
).add
(dz
.mul
(dz
))
146 # Get a new `Point3d[Float]` at an offset of `x, y, z` from `self`
149 # var origin = new Point3d[Float](1.0, 1.0, 1.0)
150 # assert origin.offset(1.0, 2.0, 3.0).to_s == "(2.0, 3.0, 4.0)"
152 fun offset
(x
, y
, z
: Numeric): Point3d[Float]
153 do return new Point3d[Float](self.x
.to_f
+x
.to_f
,
158 # 3D point with `x`, `y` and `z`
159 class Point3d[N
: Numeric]
163 redef var z
: N
= 0.0 is writable, optional
166 # Abstract 2D line segment between two ordered points
167 interface ILine[N
: Numeric]
168 # The type of points that ends the segment
171 # Point at the left-end of the segment
172 fun point_left
: P
is abstract
174 # Point at the right-end of the segment
175 fun point_right
: P
is abstract
177 redef fun to_s
do return "{point_left}--{point_right}"
180 # 2D line segment between two ordered points
181 class Line[N
: Numeric]
185 redef var point_right
198 # Abstract 3D line segment between two ordered points
199 interface ILine3d[N
: Numeric]
202 redef type P
: IPoint3d[N
]
205 # 3D line segment between two ordered points
206 class Line3d[N
: Numeric]