lib: intro the geometry module
authorAlexis Laferrière <alexis.laf@xymus.net>
Fri, 18 Apr 2014 22:00:13 +0000 (18:00 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 28 May 2014 17:36:15 +0000 (13:36 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>
Signed-off-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/geometry/boxes.nit [new file with mode: 0644]
lib/geometry/geometry.nit [new file with mode: 0644]
lib/geometry/points_and_lines.nit [new file with mode: 0644]

diff --git a/lib/geometry/boxes.nit b/lib/geometry/boxes.nit
new file mode 100644 (file)
index 0000000..61af367
--- /dev/null
@@ -0,0 +1,319 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Provides interfaces and classes to represent basic geometry needs.
+module boxes
+
+import points_and_lines
+
+# An 2d abstract bounded object
+interface Boxed[N: Numeric]
+       # Left bound
+       #
+       # require: left <= right
+       fun left: N is abstract
+
+       # Right bound
+       #
+       # require: right >= left
+       fun right: N is abstract
+
+       # Top bound
+       #
+       # require: top >= bottom
+       fun top: N is abstract
+
+       # Bottom bound
+       #
+       # require: bottom <= top
+       fun bottom: N is abstract
+
+       # Is `other` contained within `self`?
+       #
+       #     var a = new Box[Int].lbwh(1, 1, 4, 4)
+       #     var b = new Box[Int].lbwh(2, 2, 2, 2)
+       #     var c = new Box[Int].lbwh(0, 2, 8, 2)
+       #     assert a.contains(b)
+       #     assert not b.contains(a)
+       #     assert c.contains(b)
+       #     assert not b.contains(c)
+       #     assert not a.contains(c)
+       #     assert not c.contains(a)
+       fun contains(other: Boxed[N]): Bool
+       do
+               return self.top >= other.top and self.bottom <= other.bottom and
+                       self.left <= other.left and self.right >= other.right
+       end
+
+       # Does `self` intersect with `other`?
+       #
+       #     var a = new Box[Int].lbwh(0, 0, 2, 2)
+       #     var b = new Box[Int].lbwh(1, 1, 8, 2)
+       #     var c = new Box[Int].lbwh(3, 0, 2, 8)
+       #     assert a.intersects(b)
+       #     assert b.intersects(a)
+       #     assert b.intersects(c)
+       #     assert c.intersects(b)
+       #     assert not c.intersects(a)
+       #     assert not a.intersects(c)
+       fun intersects(other: Boxed[N]): Bool
+       do
+               return self.left <= other.right and other.left <= self.right and
+                       self.top >= other.bottom and other.top >= self.bottom
+       end
+end
+
+# A 2d bounded object and an implementation of `Boxed`
+#
+# This class offers many constructors specialized for different usage. They are
+# named according to the order of their arguments.
+class Box[N: Numeric]
+       super Boxed[N]
+
+       redef var left: N
+       redef var right: N
+       redef var top: N
+       redef var bottom: N
+
+       # Create a `Box` covering all of the `boxed`
+       #
+       #     var box = new Box[Int].around(new Point[Int](-4,-4), new Point[Int](4,4))
+       #     assert box.left == -4 and box.bottom == -4
+       #     assert box.right == 4 and box.top == 4
+       init around(boxed: Boxed[N]...)
+       do
+               assert not boxed.is_empty
+
+               var left: nullable N = null
+               var right: nullable N = null
+               var top: nullable N = null
+               var bottom: nullable N = null
+
+               for box in boxed do
+                       if left == null or box.left < left then left = box.left
+                       if right == null or box.right > right then right = box.right
+                       if top == null or box.top > top then top = box.top
+                       if bottom == null or box.bottom < bottom then bottom = box.bottom
+               end
+
+               assert left != null and right != null and top != null and bottom != null
+
+               self.left = left
+               self.right = right
+               self.top = top
+               self.bottom = bottom
+       end
+
+       # Create a `Box` using left, right, bottom and top
+       init lrbt(left, right, bottom, top: N)
+       do
+               self.left = left
+               self.right = right
+               self.top = top
+               self.bottom = bottom
+       end
+
+       # Create a `Box` using left, right, top and bottom
+       init lrtb(left, right, top, bottom: N)
+       do
+               self.left = left
+               self.right = right
+               self.top = top
+               self.bottom = bottom
+       end
+
+       # Create a `Box` using left, bottom, width and height
+       init lbwh(left, bottom, width, height: N)
+       do
+               self.left = left
+               self.bottom = bottom
+
+               self.right = left + width
+               self.top = bottom + height
+       end
+
+       # Create a `Box` using left, top, width and height
+       init ltwh(left, top, width, height: N)
+       do
+               self.left = left
+               self.top = top
+
+               self.right = left + width
+               self.bottom = top - height
+       end
+
+       redef fun to_s do return "<left: {left}, right: {right}, top: {top}, bottom: {bottom}>"
+end
+
+# An 3d abstract bounded object
+interface Boxed3d[N: Numeric]
+       super Boxed[N]
+
+       # Front bound
+       #
+       # require: front >= back
+       fun front: N is abstract
+
+       # Back bound
+       #
+       # require: back <= bottom
+       fun back: N is abstract
+
+       #     var a = new Box3d[Int].lbfwhd(1, 1, -1, 4, 4, 4)
+       #     var b = new Box3d[Int].lbfwhd(2, 2, -2, 2, 2, 2)
+       #     var c = new Box3d[Int].lbfwhd(2, 2,  0, 2, 2, 8)
+       #     assert a.contains(b)
+       #     assert not b.contains(a)
+       #     assert c.contains(b)
+       #     assert not b.contains(c)
+       #     assert not a.contains(c)
+       #     assert not c.contains(a)
+       redef fun contains(other)
+       do
+               return super and (not other isa Boxed3d[N] or
+                       (self.front >= other.front and self.back <= other.back))
+       end
+
+       #     var a = new Box3d[Int].lbfwhd(0, 0, 0, 2, 2, 2)
+       #     var b = new Box3d[Int].lbfwhd(1, 1, 1, 8, 2, 2)
+       #     var c = new Box3d[Int].lbfwhd(3, 0, 0, 2, 2, 8)
+       #     assert a.intersects(b)
+       #     assert b.intersects(a)
+       #     assert b.intersects(c)
+       #     assert c.intersects(b)
+       #     assert not c.intersects(a)
+       #     assert not a.intersects(c)
+       redef fun intersects(other)
+       do
+               return super and (not other isa Boxed3d[N] or
+                       (self.back <= other.front and other.back <= self.front))
+       end
+end
+
+# A 3d bounded object and an implementation of Boxed
+#
+# This class offers many constructors specialized for different usage. They are
+# named according to the order of their arguments.
+class Box3d[N: Numeric]
+       super Boxed3d[N]
+       super Box[N]
+
+       redef var front: N
+       redef var back: N
+
+       # Create a `Box` covering all of the `boxed`
+       #
+       #     var box = new Box[Int].around(new Point[Int](-4,-4), new Point[Int](4,4))
+       #     assert box.left == -4 and box.bottom == -4
+       #     assert box.right == 4 and box.top == 4
+       init around(boxed: Boxed3d[N]...)
+       do
+               assert not boxed.is_empty
+
+               var left: nullable N = null
+               var right: nullable N = null
+               var top: nullable N = null
+               var bottom: nullable N = null
+               var front: nullable N = null
+               var back: nullable N= null
+
+               for box in boxed do
+                       if left == null or box.left < left then left = box.left
+                       if right == null or box.right > right then right = box.right
+                       if top == null or box.top > top then top = box.top
+                       if bottom == null or box.bottom < bottom then bottom = box.bottom
+                       if front == null or box.front > front then front = box.front
+                       if back == null or box.back < back then back = box.back
+               end
+
+               assert left != null and right != null and top != null and bottom != null
+
+               self.left = left
+               self.right = right
+               self.top = top
+               self.bottom = bottom
+       end
+
+       # Create a `Box3d` using left, right, bottom, top, front and back
+       init lrbtfb(left, right, bottom, top, front, back: N)
+       do
+               lrbt(left, right, bottom, top)
+
+               self.front = front
+               self.back = back
+       end
+
+       # Create a `Box3d` using left, right, top, bottom, front and back
+       init lrtbfb(left, right, top, bottom, front, back: N)
+       do
+               lrtb(left, right, top, bottom)
+
+               self.front = front
+               self.back = back
+       end
+
+       # Create a `Box3d` using left, top, front, width, height and depth
+       init lbfwhd(left, bottom, front, width, height, depth: N)
+       do
+               lbwh(left, bottom, width, height)
+
+               self.front = front
+               self.back = front - depth
+       end
+
+       # Create a `Box3d` using left, top, front, width, height and depth
+       init ltfwhd(left, top, front, width, height, depth: N)
+       do
+               ltwh(left, top, width, height)
+
+               self.front = front
+               self.back = front - depth
+       end
+
+       redef fun to_s do return "<left: {left}, right: {right}, top: {top}, bottom: {bottom}, front: {front}, back: {back}"
+end
+
+redef class IPoint[N]
+       super Boxed[N]
+
+       redef fun left do return x
+       redef fun right do return x
+       redef fun top do return y
+       redef fun bottom do return y
+end
+
+redef class IPoint3d[N]
+       super Boxed3d[N]
+
+       redef fun front do return z
+       redef fun back do return z
+end
+
+redef class ILine[N]
+       super Boxed[N]
+
+       redef fun left do return point_left.x
+       redef fun right do return point_right.x
+       redef fun top do return point_left.y.min(point_right.y)
+       redef fun bottom do return point_left.y.max(point_right.y)
+end
+
+redef class ILine3d[N]
+       super Boxed3d[N]
+
+       redef fun front do return point_left.z.min(point_right.z)
+       redef fun back do return point_left.z.max(point_right.z)
+end
diff --git a/lib/geometry/geometry.nit b/lib/geometry/geometry.nit
new file mode 100644 (file)
index 0000000..d8fa6b3
--- /dev/null
@@ -0,0 +1,21 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Provides interfaces and classes to represent basic geometry needs.
+module geometry
+
+import points_and_lines
+import boxes
diff --git a/lib/geometry/points_and_lines.nit b/lib/geometry/points_and_lines.nit
new file mode 100644 (file)
index 0000000..492d31f
--- /dev/null
@@ -0,0 +1,109 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Provides interfaces and classes to represent basic geometry needs.
+module points_and_lines
+
+# An abstract 2d point, strongly linked to its implementation `Point`
+interface IPoint[N: Numeric]
+       # horizontal coordinate
+       fun x: N is abstract
+       # vertical coordinate
+       fun y: N is abstract
+
+       redef fun to_s do return "({x}, {y})"
+end
+
+# A 2d point and an implementation of `IPoint`
+class Point[N: Numeric]
+       super IPoint[N]
+
+       redef var x: N
+       redef var y: N
+
+       init(x, y: N)
+       do
+               self.x = x
+               self.y = y
+       end
+end
+
+# An abstract 3d point, strongly linked to its implementation `Point3d`
+interface IPoint3d[N: Numeric]
+       super IPoint[N]
+
+       # depth coordinate
+       fun z: N is abstract
+
+       redef fun to_s do return "({x}, {y}, {z})"
+end
+
+# A 3d point and an implementation of `IPoint3d`
+class Point3d[N: Numeric]
+       super IPoint3d[N]
+       super Point[N]
+
+       redef var z: N
+
+       init(x, y, z: N)
+       do
+               super
+               self.z = z
+       end
+end
+
+# An abstract 2d line segment
+interface ILine[N: Numeric]
+       type P: IPoint[N]
+
+       fun point_left: P is abstract
+       fun point_right: P is abstract
+
+       redef fun to_s do return "{point_left}--{point_right}"
+end
+
+# A 2d line segment
+class Line[N: Numeric]
+       super ILine[N]
+
+       redef var point_left: P
+       redef var point_right: P
+
+       init(a, b: P)
+       do
+               if a.x < b.x then
+                       point_left = a
+                       point_right = b
+               else
+                       point_left = b
+                       point_right = a
+               end
+       end
+
+end
+
+# An abstract 3d line segment
+interface ILine3d[N: Numeric]
+       super ILine[N]
+
+       redef type P: IPoint3d[N]
+end
+
+# A 3d line segment
+class Line3d[N: Numeric]
+       super Line[N]
+       super ILine3d[N]
+end