diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs
index bb6576b..f0353e0 100644
--- a/src/cgmath/lib.rs
+++ b/src/cgmath/lib.rs
@@ -30,6 +30,7 @@ pub mod vector;
pub mod angle;
pub mod plane;
pub mod point;
+pub mod line;
pub mod ray;
pub mod rotation;
pub mod transform;
diff --git a/src/cgmath/line.rs b/src/cgmath/line.rs
new file mode 100644
index 0000000..92c82a0
--- /dev/null
+++ b/src/cgmath/line.rs
@@ -0,0 +1,121 @@
+// Copyright 2013 The CGMath Developers. For a full listing of the authors,
+// refer to the AUTHORS file at the top-level directionectory of this distribution.
+//
+// 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.
+
+//! Line segments
+
+use std::num::{Zero, zero, One, one};
+
+use point::{Point, Point2, Point3};
+use vector::{Vector, Vector2};
+use partial_ord::PartOrdFloat;
+use intersect::Intersect;
+
+/// A generic directed line segment
+#[deriving(Clone, Eq)]
+pub struct Line
+{
+ pub origin: P,
+ pub dest: P,
+}
+
+impl
+<
+ S: Primitive,
+ Slice,
+ V: Vector,
+ P: Point
+> Line
+{
+ pub fn new(origin: P, dest: P) -> Line
{
+ Line { origin:origin, dest:dest }
+ }
+}
+
+pub type Line2 = Line>;
+pub type Line3 = Line>;
+
+/// Determines if an intersection between two line segments is found. If the segments are
+/// collinear and overlapping, the intersection point that will be returned will be the first
+/// intersection point found by traversing the first line segment, starting at its origin.
+impl> Intersect>> for (Line2, Line2) {
+ fn intersection(&self) -> Option> {
+ match *self {
+ (ref l1, ref l2) => {
+ let p = l1.origin;
+ let mut q = l2.origin;
+ let r = Vector2::new(l1.dest.x - l1.origin.x, l1.dest.y - l1.origin.y);
+ let mut s = Vector2::new(l2.dest.x - l2.origin.x, l2.dest.y - l2.origin.y);
+ let zero: S = Zero::zero();
+
+ let cross = r.perp_dot(&s);
+ let mut q_minus_p = Vector2::new(q.x - p.x, q.y - p.y);
+ let mut p_minus_q = Vector2::new(p.x - q.x, p.y - q.y);
+ let cross_r = q_minus_p.perp_dot(&r);
+ let cross_s = q_minus_p.perp_dot(&s);
+
+ if cross.is_zero() {
+ if cross_r.is_zero() {
+ // line segments are collinear
+
+ // special case of both lines being the same single point
+ if r.x == zero && r.y == zero && s.x == zero && s.y == zero && p == q {
+ return Some(p);
+ }
+
+ // ensure l2 (q,q+s) is pointing the same direction as l1 (p,p+r)
+ // if it is not, then swap the two endpoints of the second segment.
+ // If this is not done, the algorithm below will not find an
+ // intersection if the two directed line segments point towards the
+ // opposite segment's origin.
+ if (r.x != zero && s.x != zero && r.x.signum() != s.x.signum()) ||
+ (r.y != zero && s.y != zero && r.y.signum() != s.y.signum()) {
+ q = Point2::new(q.x + s.x, q.y + s.y);
+ s = Vector2::new(-s.x, -s.y);
+ q_minus_p = Vector2::new(q.x - p.x, q.y - p.y);
+ p_minus_q = Vector2::new(p.x - q.x, p.y - q.y);
+ }
+ let d1 = q_minus_p.dot(&r);
+ let d2 = p_minus_q.dot(&s);
+ let rdotr = r.dot(&r);
+ let sdots = s.dot(&s);
+
+ // make sure to take into account that one or both of the segments could
+ // be a single point (r.r or s.s = 0) and ignore that case
+ if (rdotr > zero && zero <= d1 && d1 <= rdotr) ||
+ (sdots > zero && zero <= d2 && d2 <= sdots) {
+ // overlapping
+ if (q_minus_p.x != zero && q_minus_p.x.signum() == r.x.signum()) ||
+ (q_minus_p.y != zero && q_minus_p.y.signum() == r.y.signum()) {
+ return Some(q);
+ }
+ return Some(p);
+ }
+ }
+ return None;
+ }
+
+ let t = cross_s / cross;
+ let u = cross_r / cross;
+
+ if zero <= t && t <= One::one() &&
+ zero <= One::one() && u <= One::one() {
+ return Some(Point2::new(p.x + t*r.x, p.y + t*r.y));
+ }
+
+ return None;
+ }
+ }
+ }
+}
diff --git a/src/test/line.rs b/src/test/line.rs
new file mode 100644
index 0000000..7184c97
--- /dev/null
+++ b/src/test/line.rs
@@ -0,0 +1,79 @@
+// Copyright 2013 The CGMath Developers. For a full listing of the authors,
+// refer to the AUTHORS file at the top-level directory of this distribution.
+//
+// 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.
+
+use cgmath::line::*;
+use cgmath::point::*;
+use cgmath::intersect::Intersect;
+
+#[test]
+fn test_line_intersection() {
+ // collinear, origins pointing towards each other, first intersection
+ // from l1.origin is in an endpoint in l2
+ let l1 = Line::new(Point2::new(0.0, 0.0), Point2::new(10.0, 0.0));
+ let l2 = Line::new(Point2::new(1.5, 0.0), Point2::new(0.5, 0.0));
+ assert_eq!((l1, l2).intersection(), Some(Point2::new(0.5, 0.0)));
+
+ // collinear, first intersection from p1.origin is at p1.origin itself
+ let l3 = Line::new(Point2::new(0.0, 0.0), Point2::new(10.0, 0.0));
+ let l4 = Line::new(Point2::new(-11.0, 0.0), Point2::new(1.0, 0.0));
+ assert_eq!((l3, l4).intersection(), Some(Point2::new(0.0, 0.0)));
+
+ // no intersection
+ let l5 = Line::new(Point2::new(5.0, 5.0), Point2::new(10.0, 6.0));
+ let l6 = Line::new(Point2::new(5.0, 4.8), Point2::new(10.0, 4.1));
+ assert_eq!((l5, l6).intersection(), None); // no intersection
+
+ // collinear, origins pointing same direction
+ let l7 = Line::new(Point2::new(0.0, 1.0), Point2::new(0.0, 0.0));
+ let l8 = Line::new(Point2::new(0.0, 0.5), Point2::new(0.0, -0.5));
+ assert_eq!((l7, l8).intersection(), Some(Point2::new(0.0, 0.5)));
+
+ // collinear, no overlap
+ let l9 = Line::new(Point2::new(0.0, 0.0), Point2::new(3.0, 0.0));
+ let l10 = Line::new(Point2::new(10.0, 0.0), Point2::new(5.0, 0.0));
+ assert_eq!((l9, l10).intersection(), None);
+
+ // intersection found
+ let l11 = Line::new(Point2::new(0.0, 0.0), Point2::new(10.0, 10.0));
+ let l12 = Line::new(Point2::new(0.0, 10.0), Point2::new(10.0, 0.0));
+ assert_eq!((l11, l12).intersection(), Some(Point2::new(5.0, 5.0)));
+
+ // special case of both lines being the same point
+ let l13 = Line::new(Point2::new(0.0, 0.0), Point2::new(0.0, 0.0));
+ let l14 = Line::new(Point2::new(0.0, 0.0), Point2::new(0.0, 0.0));
+ assert_eq!((l13, l14).intersection(), Some(Point2::new(0.0, 0.0)));
+
+ // both lines are points that are distinct
+ let l15 = Line::new(Point2::new(0.0, 0.0), Point2::new(0.0, 0.0));
+ let l16 = Line::new(Point2::new(1.0, 0.0), Point2::new(1.0, 0.0));
+ assert_eq!((l15, l16).intersection(), None);
+
+ // one line is a point that intersects the other segment
+ let l15 = Line::new(Point2::new(0.0, 0.0), Point2::new(10.0, 0.0));
+ let l16 = Line::new(Point2::new(3.0, 0.0), Point2::new(3.0, 0.0));
+ assert_eq!((l15, l16).intersection(), Some(Point2::new(3.0, 0.0)));
+
+ // one line is a point that is collinear but does not intersect with
+ // the other line
+ let l17 = Line::new(Point2::new(0.0, 0.0), Point2::new(0.0, 0.0));
+ let l18 = Line::new(Point2::new(1.0, 0.0), Point2::new(3.0, 0.0));
+ assert_eq!((l17, l18).intersection(), None);
+
+ // one line is a point that is not collinear but does not intersect
+ // with the other line
+ let l19 = Line::new(Point2::new(0.0, 0.0), Point2::new(0.0, 0.0));
+ let l20 = Line::new(Point2::new(1.0, 0.0), Point2::new(2.0, 10.0));
+ assert_eq!((l19, l20).intersection(), None);
+}
diff --git a/src/test/test.rs b/src/test/test.rs
index 9449f1d..43ccefd 100644
--- a/src/test/test.rs
+++ b/src/test/test.rs
@@ -26,6 +26,7 @@ pub mod vector;
pub mod angle;
pub mod plane;
pub mod point;
+pub mod line;
// pub mod ray;
// pub mod rotation;
pub mod transform;