parent
9e87f5507d
commit
943a92e691
22 changed files with 4 additions and 1245 deletions
|
@ -17,14 +17,8 @@ The library provides:
|
||||||
- rotation matrices: `Basis2`, `Basis3`
|
- rotation matrices: `Basis2`, `Basis3`
|
||||||
- angle units: `Rad`, `Deg`
|
- angle units: `Rad`, `Deg`
|
||||||
- points: `Point2`, `Point3`
|
- points: `Point2`, `Point3`
|
||||||
- a generic ray: `Ray`
|
|
||||||
- a plane type: `Plane`
|
|
||||||
- perspective projections: `Perspective`, `PerspectiveFov`, `Ortho`
|
- perspective projections: `Perspective`, `PerspectiveFov`, `Ortho`
|
||||||
- a view frustum: `Frustum`
|
|
||||||
- spatial transformations: `AffineMatrix3`, `Transform3`
|
- spatial transformations: `AffineMatrix3`, `Transform3`
|
||||||
- axis-aligned bounding boxes: `Aabb2`, `Aabb3`
|
|
||||||
- oriented bounding boxes: `Obb2`, `Obb3`
|
|
||||||
- collision primitives: `Sphere`, `Cylinder`
|
|
||||||
|
|
||||||
Not all of the functionality has been implemented yet, and the existing code
|
Not all of the functionality has been implemented yet, and the existing code
|
||||||
is not fully covered by the testsuite. If you encounter any mistakes or
|
is not fully covered by the testsuite. If you encounter any mistakes or
|
||||||
|
|
256
src/aabb.rs
256
src/aabb.rs
|
@ -1,256 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! Axis-aligned bounding boxes
|
|
||||||
//!
|
|
||||||
//! An AABB is a geometric object which encompasses a set of points and is not
|
|
||||||
//! rotated. It is either a rectangle or a rectangular prism (depending on the
|
|
||||||
//! dimension) where the slope of every line is either 0 or undefined. These
|
|
||||||
//! are useful for very cheap collision detection.
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use rust_num::{Float, Zero, One};
|
|
||||||
|
|
||||||
use bound::*;
|
|
||||||
use point::{Point, Point2, Point3};
|
|
||||||
use vector::{Vector, Vector2, Vector3};
|
|
||||||
use ray::{Ray2};
|
|
||||||
use intersect::Intersect;
|
|
||||||
use num::{BaseNum, BaseFloat};
|
|
||||||
use plane::Plane;
|
|
||||||
|
|
||||||
|
|
||||||
pub trait Aabb<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
|
|
||||||
/// Create a new AABB using two points as opposing corners.
|
|
||||||
fn new(p1: P, p2: P) -> Self;
|
|
||||||
|
|
||||||
/// Return a shared reference to the point nearest to (-inf, -inf).
|
|
||||||
fn min<'a>(&'a self) -> &'a P;
|
|
||||||
|
|
||||||
/// Return a shared reference to the point nearest to (inf, inf).
|
|
||||||
fn max<'a>(&'a self) -> &'a P;
|
|
||||||
|
|
||||||
/// Return the dimensions of this AABB.
|
|
||||||
#[inline]
|
|
||||||
fn dim(&self) -> V { self.max().sub_p(self.min()) }
|
|
||||||
|
|
||||||
/// Return the volume this AABB encloses.
|
|
||||||
#[inline]
|
|
||||||
fn volume(&self) -> S { self.dim().product() }
|
|
||||||
|
|
||||||
/// Return the center point of this AABB.
|
|
||||||
#[inline]
|
|
||||||
fn center(&self) -> P {
|
|
||||||
let two = S::one() + S::one();
|
|
||||||
self.min().add_v(&self.dim().div_s(two))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tests whether a point is cointained in the box, inclusive for min corner
|
|
||||||
/// and exclusive for the max corner.
|
|
||||||
#[inline]
|
|
||||||
fn contains(&self, p: &P) -> bool;
|
|
||||||
|
|
||||||
/// Returns a new AABB that is grown to include the given point.
|
|
||||||
fn grow(&self, p: &P) -> Self {
|
|
||||||
let min = self.min().min(p);
|
|
||||||
let max = self.max().max(p);
|
|
||||||
Aabb::new(min, max)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a vector to every point in the AABB, returning a new AABB.
|
|
||||||
fn add_v(&self, v: &V) -> Self {
|
|
||||||
Aabb::new(self.min().add_v(v), self.max().add_v(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiply every point in the AABB by a scalar, returning a new AABB.
|
|
||||||
fn mul_s(&self, s: S) -> Self {
|
|
||||||
Aabb::new(self.min().mul_s(s.clone()), self.max().mul_s(s.clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiply every point in the AABB by a vector, returning a new AABB.
|
|
||||||
fn mul_v(&self, v: &V) -> Self {
|
|
||||||
let min = P::from_vec(&self.min().to_vec().mul_v(v));
|
|
||||||
let max = P::from_vec(&self.max().to_vec().mul_v(v));
|
|
||||||
Aabb::new(min, max)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A two-dimensional AABB, aka a rectangle.
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Aabb2<S> {
|
|
||||||
pub min: Point2<S>,
|
|
||||||
pub max: Point2<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> Aabb2<S> {
|
|
||||||
/// Construct a new axis-aligned bounding box from two points.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> {
|
|
||||||
Aabb2 {
|
|
||||||
min: Point2::new(p1.x.partial_min(p2.x),
|
|
||||||
p1.y.partial_min(p2.y)),
|
|
||||||
max: Point2::new(p1.x.partial_max(p2.x),
|
|
||||||
p1.y.partial_max(p2.y)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute corners.
|
|
||||||
#[inline]
|
|
||||||
pub fn to_corners(&self) -> [Point2<S>; 4] {
|
|
||||||
[self.min,
|
|
||||||
Point2::new(self.max.x, self.min.y),
|
|
||||||
Point2::new(self.min.x, self.max.y),
|
|
||||||
self.max]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> Aabb<S, Vector2<S>, Point2<S>> for Aabb2<S> {
|
|
||||||
#[inline]
|
|
||||||
fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> { Aabb2::new(p1, p2) }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn min<'a>(&'a self) -> &'a Point2<S> { &self.min }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn max<'a>(&'a self) -> &'a Point2<S> { &self.max }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn contains(&self, p: &Point2<S>) -> bool {
|
|
||||||
let v_min = p.sub_p(self.min());
|
|
||||||
let v_max = self.max().sub_p(p);
|
|
||||||
v_min.x >= S::zero() && v_min.y >= S::zero() &&
|
|
||||||
v_max.x > S::zero() && v_max.y > S::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> fmt::Debug for Aabb2<S> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A three-dimensional AABB, aka a rectangular prism.
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Aabb3<S> {
|
|
||||||
pub min: Point3<S>,
|
|
||||||
pub max: Point3<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> Aabb3<S> {
|
|
||||||
/// Construct a new axis-aligned bounding box from two points.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> {
|
|
||||||
Aabb3 {
|
|
||||||
min: Point3::new(p1.x.partial_min(p2.x),
|
|
||||||
p1.y.partial_min(p2.y),
|
|
||||||
p1.z.partial_min(p2.z)),
|
|
||||||
max: Point3::new(p1.x.partial_max(p2.x),
|
|
||||||
p1.y.partial_max(p2.y),
|
|
||||||
p1.z.partial_max(p2.z)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute corners.
|
|
||||||
#[inline]
|
|
||||||
pub fn to_corners(&self) -> [Point3<S>; 8] {
|
|
||||||
[self.min,
|
|
||||||
Point3::new(self.max.x, self.min.y, self.min.z),
|
|
||||||
Point3::new(self.min.x, self.max.y, self.min.z),
|
|
||||||
Point3::new(self.max.x, self.max.y, self.min.z),
|
|
||||||
Point3::new(self.min.x, self.min.y, self.max.z),
|
|
||||||
Point3::new(self.max.x, self.min.y, self.max.z),
|
|
||||||
Point3::new(self.min.x, self.max.y, self.max.z),
|
|
||||||
self.max]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> Aabb<S, Vector3<S>, Point3<S>> for Aabb3<S> {
|
|
||||||
#[inline]
|
|
||||||
fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> { Aabb3::new(p1, p2) }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn min<'a>(&'a self) -> &'a Point3<S> { &self.min }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn max<'a>(&'a self) -> &'a Point3<S> { &self.max }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn contains(&self, p: &Point3<S>) -> bool {
|
|
||||||
let v_min = p.sub_p(self.min());
|
|
||||||
let v_max = self.max().sub_p(p);
|
|
||||||
v_min.x >= S::zero() && v_min.y >= S::zero() && v_min.z >= S::zero() &&
|
|
||||||
v_max.x > S::zero() && v_max.y > S::zero() && v_max.z > S::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum> fmt::Debug for Aabb3<S> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Aabb2<S>) {
|
|
||||||
fn intersection(&self) -> Option<Point2<S>> {
|
|
||||||
let (ref ray, ref aabb) = *self;
|
|
||||||
|
|
||||||
let mut tmin = S::neg_infinity();
|
|
||||||
let mut tmax = S::infinity();
|
|
||||||
|
|
||||||
if ray.direction.x != S::zero() {
|
|
||||||
let tx1 = (aabb.min.x - ray.origin.x) / ray.direction.x;
|
|
||||||
let tx2 = (aabb.max.x - ray.origin.x) / ray.direction.x;
|
|
||||||
tmin = tmin.max(tx1.min(tx2));
|
|
||||||
tmax = tmax.min(tx1.max(tx2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ray.direction.y != S::zero() {
|
|
||||||
let ty1 = (aabb.min.y - ray.origin.y) / ray.direction.y;
|
|
||||||
let ty2 = (aabb.max.y - ray.origin.y) / ray.direction.y;
|
|
||||||
tmin = tmin.max(ty1.min(ty2));
|
|
||||||
tmax = tmax.min(ty1.max(ty2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if tmin < S::zero() && tmax < S::zero() {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else if tmax >= tmin {
|
|
||||||
if tmin >= S::zero() {
|
|
||||||
Some(Point2::new(ray.origin.x + ray.direction.x * tmin,
|
|
||||||
ray.origin.y + ray.direction.y * tmin))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Some(Point2::new(ray.origin.x + ray.direction.x * tmax,
|
|
||||||
ray.origin.y + ray.direction.y * tmax))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static> Bound<S> for Aabb3<S> {
|
|
||||||
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
|
|
||||||
let corners = self.to_corners();
|
|
||||||
let first = corners[0].relate_plane(plane);
|
|
||||||
for p in corners[1..].iter() {
|
|
||||||
if p.relate_plane(plane) != first {
|
|
||||||
return Relation::Cross;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
first
|
|
||||||
}
|
|
||||||
}
|
|
46
src/bound.rs
46
src/bound.rs
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2013-2014 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.
|
|
||||||
|
|
||||||
//! Generic spatial bounds.
|
|
||||||
|
|
||||||
use matrix::Matrix4;
|
|
||||||
use num::BaseFloat;
|
|
||||||
use plane::Plane;
|
|
||||||
|
|
||||||
/// Spatial relation between two objects.
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum Relation {
|
|
||||||
/// Completely inside.
|
|
||||||
In,
|
|
||||||
/// Crosses the boundary.
|
|
||||||
Cross,
|
|
||||||
/// Completely outside.
|
|
||||||
Out,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic bound.
|
|
||||||
pub trait Bound<S: BaseFloat + 'static>: Sized {
|
|
||||||
/// Classify the spatial relation with a plane.
|
|
||||||
fn relate_plane(&self, &Plane<S>) -> Relation;
|
|
||||||
/// Classify the relation with a projection matrix.
|
|
||||||
fn relate_clip_space(&self, projection: &Matrix4<S>) -> Relation {
|
|
||||||
use frustum::Frustum;
|
|
||||||
match Frustum::from_matrix4(*projection) {
|
|
||||||
Some(f) => f.contains(self),
|
|
||||||
None => Relation::Cross,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! Oriented bounding cylinder
|
|
||||||
|
|
||||||
use point::Point3;
|
|
||||||
use vector::Vector3;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Cylinder<S> {
|
|
||||||
pub center: Point3<S>,
|
|
||||||
pub axis: Vector3<S>,
|
|
||||||
pub radius: S,
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! View frustum for visibility determination
|
|
||||||
|
|
||||||
use array::Array2;
|
|
||||||
use bound::*;
|
|
||||||
use matrix::Matrix4;
|
|
||||||
use num::BaseFloat;
|
|
||||||
use plane::Plane;
|
|
||||||
use point::Point3;
|
|
||||||
use vector::{Vector, EuclideanVector};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Frustum<S: BaseFloat> {
|
|
||||||
pub left: Plane<S>,
|
|
||||||
pub right: Plane<S>,
|
|
||||||
pub bottom: Plane<S>,
|
|
||||||
pub top: Plane<S>,
|
|
||||||
pub near: Plane<S>,
|
|
||||||
pub far: Plane<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static>
|
|
||||||
Frustum<S> {
|
|
||||||
/// Construct a frustum.
|
|
||||||
pub fn new(left: Plane<S>, right: Plane<S>,
|
|
||||||
bottom: Plane<S>, top: Plane<S>,
|
|
||||||
near: Plane<S>, far: Plane<S>) -> Frustum<S> {
|
|
||||||
Frustum {
|
|
||||||
left: left,
|
|
||||||
right: right,
|
|
||||||
bottom: bottom,
|
|
||||||
top: top,
|
|
||||||
near: near,
|
|
||||||
far: far,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract frustum planes from a projection matrix.
|
|
||||||
pub fn from_matrix4(mat: Matrix4<S>) -> Option<Frustum<S>> {
|
|
||||||
Some(Frustum::new(
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(0))).normalize()
|
|
||||||
{ Some(p) => p, None => return None },
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(0))).normalize()
|
|
||||||
{ Some(p) => p, None => return None },
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(1))).normalize()
|
|
||||||
{ Some(p) => p, None => return None },
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(1))).normalize()
|
|
||||||
{ Some(p) => p, None => return None },
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(2))).normalize()
|
|
||||||
{ Some(p) => p, None => return None },
|
|
||||||
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(2))).normalize()
|
|
||||||
{ Some(p) => p, None => return None }
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the spatial relation of a bound inside this frustum.
|
|
||||||
pub fn contains<B: Bound<S>>(&self, bound: &B) -> Relation {
|
|
||||||
[&self.left, &self.right, &self.top, &self.bottom, &self.near, &self.far]
|
|
||||||
.iter().fold(Relation::In, |cur, p| {
|
|
||||||
use std::cmp::max;
|
|
||||||
let r = bound.relate_plane(p);
|
|
||||||
// If any of the planes are `Out`, the bound is outside.
|
|
||||||
// Otherwise, if any are `Cross`, the bound is crossing.
|
|
||||||
// Otherwise, the bound is fully inside.
|
|
||||||
max(cur, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct FrustumPoints<S> {
|
|
||||||
pub near_top_left: Point3<S>,
|
|
||||||
pub near_top_right: Point3<S>,
|
|
||||||
pub near_bottom_left: Point3<S>,
|
|
||||||
pub near_bottom_right: Point3<S>,
|
|
||||||
pub far_top_left: Point3<S>,
|
|
||||||
pub far_top_right: Point3<S>,
|
|
||||||
pub far_bottom_left: Point3<S>,
|
|
||||||
pub far_bottom_right: Point3<S>,
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
pub trait Intersect<Result> {
|
|
||||||
fn intersection(&self) -> Result;
|
|
||||||
}
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -42,23 +42,12 @@ pub use quaternion::*;
|
||||||
pub use vector::*;
|
pub use vector::*;
|
||||||
|
|
||||||
pub use angle::*;
|
pub use angle::*;
|
||||||
pub use plane::Plane;
|
|
||||||
pub use point::*;
|
pub use point::*;
|
||||||
pub use line::*;
|
|
||||||
pub use ray::*;
|
|
||||||
pub use rotation::*;
|
pub use rotation::*;
|
||||||
pub use transform::*;
|
pub use transform::*;
|
||||||
|
|
||||||
pub use projection::*;
|
pub use projection::*;
|
||||||
|
|
||||||
pub use aabb::*;
|
|
||||||
pub use bound::*;
|
|
||||||
pub use cylinder::Cylinder;
|
|
||||||
pub use frustum::{Frustum, FrustumPoints};
|
|
||||||
pub use intersect::Intersect;
|
|
||||||
pub use obb::*;
|
|
||||||
pub use sphere::Sphere;
|
|
||||||
|
|
||||||
pub use approx::ApproxEq;
|
pub use approx::ApproxEq;
|
||||||
pub use num::*;
|
pub use num::*;
|
||||||
|
|
||||||
|
@ -73,22 +62,11 @@ mod quaternion;
|
||||||
mod vector;
|
mod vector;
|
||||||
|
|
||||||
mod angle;
|
mod angle;
|
||||||
mod plane;
|
|
||||||
mod point;
|
mod point;
|
||||||
mod line;
|
|
||||||
mod ray;
|
|
||||||
mod rotation;
|
mod rotation;
|
||||||
mod transform;
|
mod transform;
|
||||||
|
|
||||||
mod projection;
|
mod projection;
|
||||||
|
|
||||||
mod aabb;
|
|
||||||
mod bound;
|
|
||||||
mod cylinder;
|
|
||||||
mod frustum;
|
|
||||||
mod intersect;
|
|
||||||
mod obb;
|
|
||||||
mod sphere;
|
|
||||||
|
|
||||||
mod approx;
|
mod approx;
|
||||||
mod num;
|
mod num;
|
||||||
|
|
100
src/line.rs
100
src/line.rs
|
@ -1,100 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! Line segments
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use rust_num::{Zero, One};
|
|
||||||
|
|
||||||
use num::{BaseNum, BaseFloat};
|
|
||||||
use point::{Point, Point2, Point3};
|
|
||||||
use vector::{Vector, Vector2, Vector3};
|
|
||||||
use ray::{Ray2};
|
|
||||||
use intersect::Intersect;
|
|
||||||
|
|
||||||
/// A generic directed line segment from `origin` to `dest`.
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Line<S, V, P> {
|
|
||||||
pub origin: P,
|
|
||||||
pub dest: P,
|
|
||||||
phantom_s: PhantomData<S>,
|
|
||||||
phantom_v: PhantomData<V>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Line<S, V, P> {
|
|
||||||
pub fn new(origin: P, dest: P) -> Line<S, V, P> {
|
|
||||||
Line {
|
|
||||||
origin: origin,
|
|
||||||
dest: dest,
|
|
||||||
phantom_v: PhantomData,
|
|
||||||
phantom_s: PhantomData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Line2<S> = Line<S, Vector2<S>, Point2<S>>;
|
|
||||||
pub type Line3<S> = Line<S, Vector3<S>, Point3<S>>;
|
|
||||||
|
|
||||||
/// Determines if an intersection between a ray and a line segment is found.
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Line2<S>) {
|
|
||||||
fn intersection(&self) -> Option<Point2<S>> {
|
|
||||||
let (ref ray, ref line) = *self;
|
|
||||||
|
|
||||||
let p = ray.origin;
|
|
||||||
let q = line.origin;
|
|
||||||
let r = ray.direction;
|
|
||||||
let s = Vector2::new(line.dest.x - line.origin.x, line.dest.y - line.origin.y);
|
|
||||||
|
|
||||||
let cross_1 = r.perp_dot(&s);
|
|
||||||
let qmp = Vector2::new(q.x - p.x, q.y - p.y);
|
|
||||||
let cross_2 = qmp.perp_dot(&r);
|
|
||||||
|
|
||||||
if cross_1 == S::zero() {
|
|
||||||
if cross_2 != S::zero() {
|
|
||||||
// parallel
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// collinear
|
|
||||||
let q2mp = Vector2::new(line.dest.x - p.x, line.dest.y - p.y);
|
|
||||||
let dot_1 = qmp.dot(&r);
|
|
||||||
let dot_2 = q2mp.dot(&r);
|
|
||||||
if (dot_1 <= S::zero() && dot_2 >= S::zero()) || (dot_1 >= S::zero() && dot_2 <= S::zero()) {
|
|
||||||
return Some(p);
|
|
||||||
}
|
|
||||||
else if dot_1 >= S::zero() && dot_2 >= S::zero() {
|
|
||||||
if dot_1 <= dot_2 {
|
|
||||||
return Some(q);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Some(line.dest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no overlap exists
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let t = qmp.perp_dot(&s) / cross_1;
|
|
||||||
let u = cross_2 / cross_1;
|
|
||||||
|
|
||||||
if S::zero() <= t && u >= S::zero() && u <= S::one() {
|
|
||||||
return Some(Point2::new(p.x + t*r.x, p.y + t*r.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
33
src/obb.rs
33
src/obb.rs
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! Oriented bounding boxes
|
|
||||||
|
|
||||||
use point::{Point2, Point3};
|
|
||||||
use vector::{Vector2, Vector3};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Obb2<S> {
|
|
||||||
pub center: Point2<S>,
|
|
||||||
pub axis: Vector2<S>,
|
|
||||||
pub extents: Vector2<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Obb3<S> {
|
|
||||||
pub center: Point3<S>,
|
|
||||||
pub axis: Vector3<S>,
|
|
||||||
pub extents: Vector3<S>,
|
|
||||||
}
|
|
150
src/plane.rs
150
src/plane.rs
|
@ -1,150 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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 std::fmt;
|
|
||||||
|
|
||||||
use rust_num::{One, Zero};
|
|
||||||
|
|
||||||
use approx::ApproxEq;
|
|
||||||
use intersect::Intersect;
|
|
||||||
use num::{BaseFloat};
|
|
||||||
use point::{Point, Point3};
|
|
||||||
use ray::Ray3;
|
|
||||||
use vector::{Vector3, Vector4};
|
|
||||||
use vector::{Vector, EuclideanVector};
|
|
||||||
|
|
||||||
|
|
||||||
/// A 3-dimensional plane formed from the equation: `A*x + B*y + C*z - D = 0`.
|
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// - `n`: a unit vector representing the normal of the plane where:
|
|
||||||
/// - `n.x`: corresponds to `A` in the plane equation
|
|
||||||
/// - `n.y`: corresponds to `B` in the plane equation
|
|
||||||
/// - `n.z`: corresponds to `C` in the plane equation
|
|
||||||
/// - `d`: the distance value, corresponding to `D` in the plane equation
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
///
|
|
||||||
/// The `A*x + B*y + C*z - D = 0` form is preferred over the other common
|
|
||||||
/// alternative, `A*x + B*y + C*z + D = 0`, because it tends to avoid
|
|
||||||
/// superfluous negations (see _Real Time Collision Detection_, p. 55).
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Plane<S> {
|
|
||||||
pub n: Vector3<S>,
|
|
||||||
pub d: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Plane<S> {
|
|
||||||
/// Construct a plane from a normal vector and a scalar distance. The
|
|
||||||
/// plane will be perpendicular to `n`, and `d` units offset from the
|
|
||||||
/// origin.
|
|
||||||
pub fn new(n: Vector3<S>, d: S) -> Plane<S> {
|
|
||||||
Plane { n: n, d: d }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// - `a`: the `x` component of the normal
|
|
||||||
/// - `b`: the `y` component of the normal
|
|
||||||
/// - `c`: the `z` component of the normal
|
|
||||||
/// - `d`: the plane's distance value
|
|
||||||
pub fn from_abcd(a: S, b: S, c: S, d: S) -> Plane<S> {
|
|
||||||
Plane { n: Vector3::new(a, b, c), d: d }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a plane from the components of a four-dimensional vector
|
|
||||||
pub fn from_vector4(v: Vector4<S>) -> Plane<S> {
|
|
||||||
Plane { n: Vector3::new(v.x, v.y, v.z), d: v.w }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a plane from the components of a four-dimensional vector
|
|
||||||
/// Assuming alternative representation: `A*x + B*y + C*z + D = 0`
|
|
||||||
pub fn from_vector4_alt(v: Vector4<S>) -> Plane<S> {
|
|
||||||
Plane { n: Vector3::new(v.x, v.y, v.z), d: -v.w }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
|
|
||||||
pub fn from_points(a: Point3<S>, b: Point3<S>, c: Point3<S>) -> Option<Plane<S>> {
|
|
||||||
// create two vectors that run parallel to the plane
|
|
||||||
let v0 = b.sub_p(&a);
|
|
||||||
let v1 = c.sub_p(&a);
|
|
||||||
|
|
||||||
// find the normal vector that is perpendicular to v1 and v2
|
|
||||||
let mut n = v0.cross(&v1);
|
|
||||||
|
|
||||||
if n.approx_eq(&Vector3::zero()) { None }
|
|
||||||
else {
|
|
||||||
// compute the normal and the distance to the plane
|
|
||||||
n.normalize_self();
|
|
||||||
let d = -a.dot(&n);
|
|
||||||
|
|
||||||
Some(Plane::new(n, d))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a plane from a point and a normal vector.
|
|
||||||
/// The plane will contain the point `p` and be perpendicular to `n`.
|
|
||||||
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
|
|
||||||
Plane { n: n, d: p.dot(&n) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Normalize a plane.
|
|
||||||
pub fn normalize(&self) -> Option<Plane<S>> {
|
|
||||||
if self.n.approx_eq(&Vector3::zero()) { None }
|
|
||||||
else {
|
|
||||||
let denom = S::one() / self.n.length();
|
|
||||||
Some(Plane::new(self.n.mul_s(denom), self.d*denom))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) {
|
|
||||||
fn intersection(&self) -> Option<Point3<S>> {
|
|
||||||
let (ref p, ref r) = *self;
|
|
||||||
|
|
||||||
let t = -(p.d + r.origin.dot(&p.n)) / r.direction.dot(&p.n);
|
|
||||||
if t < Zero::zero() { None }
|
|
||||||
else { Some(r.origin.add_v(&r.direction.mul_s(t))) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Ray3<S>>> for (Plane<S>, Plane<S>) {
|
|
||||||
fn intersection(&self) -> Option<Ray3<S>> {
|
|
||||||
panic!("Not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Plane<S>, Plane<S>) {
|
|
||||||
fn intersection(&self) -> Option<Point3<S>> {
|
|
||||||
panic!("Not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat + ApproxEq<S>>
|
|
||||||
ApproxEq<S> for Plane<S> {
|
|
||||||
#[inline]
|
|
||||||
fn approx_eq_eps(&self, other: &Plane<S>, epsilon: &S) -> bool {
|
|
||||||
self.n.approx_eq_eps(&other.n, epsilon) &&
|
|
||||||
self.d.approx_eq_eps(&other.d, epsilon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> fmt::Debug for Plane<S> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{:?}x + {:?}y + {:?}z - {:?} = 0",
|
|
||||||
self.n.x, self.n.y, self.n.z, self.d)
|
|
||||||
}
|
|
||||||
}
|
|
27
src/point.rs
27
src/point.rs
|
@ -25,10 +25,8 @@ use rust_num::{One, Zero};
|
||||||
|
|
||||||
use approx::ApproxEq;
|
use approx::ApproxEq;
|
||||||
use array::Array1;
|
use array::Array1;
|
||||||
use bound::*;
|
use matrix::Matrix;
|
||||||
use matrix::{Matrix, Matrix4};
|
|
||||||
use num::{BaseNum, BaseFloat};
|
use num::{BaseNum, BaseFloat};
|
||||||
use plane::Plane;
|
|
||||||
use vector::*;
|
use vector::*;
|
||||||
|
|
||||||
/// A point in 2-dimensional space.
|
/// A point in 2-dimensional space.
|
||||||
|
@ -470,29 +468,6 @@ impl<S: BaseNum> fmt::Debug for Point3<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static> Bound<S> for Point3<S> {
|
|
||||||
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
|
|
||||||
let dist = self.dot(&plane.n);
|
|
||||||
if dist > plane.d {
|
|
||||||
Relation::In
|
|
||||||
}else if dist < plane.d {
|
|
||||||
Relation::Out
|
|
||||||
}else {
|
|
||||||
Relation::Cross
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_clip_space(&self, projection: &Matrix4<S>) -> Relation {
|
|
||||||
use std::cmp::Ordering::*;
|
|
||||||
let p = projection.mul_v(&self.to_homogeneous());
|
|
||||||
match (p.x.abs().partial_cmp(&p.w), p.y.abs().partial_cmp(&p.w), p.z.abs().partial_cmp(&p.w)) {
|
|
||||||
(Some(Less), Some(Less), Some(Less)) => Relation::In,
|
|
||||||
(Some(Greater), _, _) | (_, Some(Greater), _) | (_, _, Some(Greater)) => Relation::Out,
|
|
||||||
_ => Relation::Cross,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
mod point2 {
|
mod point2 {
|
||||||
|
|
|
@ -17,10 +17,8 @@ use rust_num::{Zero, One};
|
||||||
use rust_num::traits::cast;
|
use rust_num::traits::cast;
|
||||||
|
|
||||||
use angle::{Angle, Rad, tan, cot};
|
use angle::{Angle, Rad, tan, cot};
|
||||||
use frustum::Frustum;
|
|
||||||
use matrix::Matrix4;
|
use matrix::Matrix4;
|
||||||
use num::BaseFloat;
|
use num::BaseFloat;
|
||||||
use plane::Plane;
|
|
||||||
|
|
||||||
/// Create a perspective projection matrix.
|
/// Create a perspective projection matrix.
|
||||||
///
|
///
|
||||||
|
@ -65,10 +63,6 @@ pub fn ortho<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near:
|
||||||
}.into()
|
}.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Projection<S: BaseFloat>: Into<Matrix4<S>> {
|
|
||||||
fn to_frustum(&self) -> Frustum<S>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A perspective projection based on a vertical field-of-view angle.
|
/// A perspective projection based on a vertical field-of-view angle.
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||||
pub struct PerspectiveFov<S, A> {
|
pub struct PerspectiveFov<S, A> {
|
||||||
|
@ -96,13 +90,6 @@ impl<S: BaseFloat, A: Angle<S>> PerspectiveFov<S, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
|
|
||||||
fn to_frustum(&self) -> Frustum<S> {
|
|
||||||
// TODO: Could this be faster?
|
|
||||||
Frustum::from_matrix4(self.clone().into()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat, A: Angle<S>> From<PerspectiveFov<S, A>> for Matrix4<S> {
|
impl<S: BaseFloat, A: Angle<S>> From<PerspectiveFov<S, A>> for Matrix4<S> {
|
||||||
fn from(persp: PerspectiveFov<S, A>) -> Matrix4<S> {
|
fn from(persp: PerspectiveFov<S, A>) -> Matrix4<S> {
|
||||||
let half_turn: A = Angle::turn_div_2();
|
let half_turn: A = Angle::turn_div_2();
|
||||||
|
@ -156,13 +143,6 @@ pub struct Perspective<S> {
|
||||||
pub far: S,
|
pub far: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
|
|
||||||
fn to_frustum(&self) -> Frustum<S> {
|
|
||||||
// TODO: Could this be faster?
|
|
||||||
Frustum::from_matrix4(self.clone().into()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static> From<Perspective<S>> for Matrix4<S> {
|
impl<S: BaseFloat + 'static> From<Perspective<S>> for Matrix4<S> {
|
||||||
fn from(persp: Perspective<S>) -> Matrix4<S> {
|
fn from(persp: Perspective<S>) -> Matrix4<S> {
|
||||||
assert!(persp.left <= persp.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", persp.left, persp.right);
|
assert!(persp.left <= persp.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", persp.left, persp.right);
|
||||||
|
@ -209,19 +189,6 @@ pub struct Ortho<S> {
|
||||||
pub far: S,
|
pub far: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: BaseFloat> Projection<S> for Ortho<S> {
|
|
||||||
fn to_frustum(&self) -> Frustum<S> {
|
|
||||||
Frustum {
|
|
||||||
left: Plane::from_abcd( S::one(), S::zero(), S::zero(), self.left.clone()),
|
|
||||||
right: Plane::from_abcd(-S::one(), S::zero(), S::zero(), self.right.clone()),
|
|
||||||
bottom: Plane::from_abcd(S::zero(), S::one(), S::zero(), self.bottom.clone()),
|
|
||||||
top: Plane::from_abcd(S::zero(), -S::one(), S::zero(), self.top.clone()),
|
|
||||||
near: Plane::from_abcd(S::zero(), S::zero(), -S::one(), self.near.clone()),
|
|
||||||
far: Plane::from_abcd(S::zero(), S::zero(), S::one(), self.far.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
|
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
|
||||||
fn from(ortho: Ortho<S>) -> Matrix4<S> {
|
fn from(ortho: Ortho<S>) -> Matrix4<S> {
|
||||||
let two: S = cast(2i8).unwrap();
|
let two: S = cast(2i8).unwrap();
|
||||||
|
|
41
src/ray.rs
41
src/ray.rs
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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 std::marker::PhantomData;
|
|
||||||
use num::BaseNum;
|
|
||||||
use point::{Point, Point2, Point3};
|
|
||||||
use vector::{Vector, Vector2, Vector3};
|
|
||||||
|
|
||||||
/// A generic ray starting at `origin` and extending infinitely in
|
|
||||||
/// `direction`.
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Ray<S, P, V> {
|
|
||||||
pub origin: P,
|
|
||||||
pub direction: V,
|
|
||||||
phantom_s: PhantomData<S>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Ray<S, P, V> {
|
|
||||||
pub fn new(origin: P, direction: V) -> Ray<S, P, V> {
|
|
||||||
Ray {
|
|
||||||
origin: origin,
|
|
||||||
direction: direction,
|
|
||||||
phantom_s: PhantomData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Ray2<S> = Ray<S, Point2<S>, Vector2<S>>;
|
|
||||||
pub type Ray3<S> = Ray<S, Point3<S>, Vector3<S>>;
|
|
|
@ -21,7 +21,6 @@ use matrix::Matrix3;
|
||||||
use num::BaseFloat;
|
use num::BaseFloat;
|
||||||
use point::{Point, Point2, Point3};
|
use point::{Point, Point2, Point3};
|
||||||
use quaternion::Quaternion;
|
use quaternion::Quaternion;
|
||||||
use ray::Ray;
|
|
||||||
use vector::{Vector, Vector2, Vector3};
|
use vector::{Vector, Vector2, Vector3};
|
||||||
|
|
||||||
/// A trait for a generic rotation. A rotation is a transformation that
|
/// A trait for a generic rotation. A rotation is a transformation that
|
||||||
|
@ -47,12 +46,6 @@ pub trait Rotation<S: BaseFloat, V: Vector<S>, P: Point<S, V>>: PartialEq + Appr
|
||||||
P::from_vec(&self.rotate_vector(&point.to_vec()))
|
P::from_vec(&self.rotate_vector(&point.to_vec()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rotate a ray using this rotation.
|
|
||||||
#[inline]
|
|
||||||
fn rotate_ray(&self, ray: &Ray<S, P, V>) -> Ray<S, P,V> {
|
|
||||||
Ray::new(ray.origin.clone(), self.rotate_vector(&ray.direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new rotation which combines both this rotation, and another.
|
/// Create a new rotation which combines both this rotation, and another.
|
||||||
fn concat(&self, other: &Self) -> Self;
|
fn concat(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
//! Bounding sphere
|
|
||||||
|
|
||||||
use rust_num::Zero;
|
|
||||||
|
|
||||||
use bound::*;
|
|
||||||
use intersect::Intersect;
|
|
||||||
use num::BaseFloat;
|
|
||||||
use point::{Point, Point3};
|
|
||||||
use plane::Plane;
|
|
||||||
use ray::Ray3;
|
|
||||||
use vector::Vector;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
|
||||||
pub struct Sphere<S> {
|
|
||||||
pub center: Point3<S>,
|
|
||||||
pub radius: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Sphere<S>, Ray3<S>) {
|
|
||||||
fn intersection(&self) -> Option<Point3<S>> {
|
|
||||||
let (ref s, ref r) = *self;
|
|
||||||
|
|
||||||
let l = s.center.sub_p(&r.origin);
|
|
||||||
let tca = l.dot(&r.direction);
|
|
||||||
if tca < S::zero() { return None; }
|
|
||||||
let d2 = l.dot(&l) - tca*tca;
|
|
||||||
if d2 > s.radius*s.radius { return None; }
|
|
||||||
let thc = (s.radius*s.radius - d2).sqrt();
|
|
||||||
Some(r.origin.add_v(&r.direction.mul_s(tca - thc)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static> Bound<S> for Sphere<S> {
|
|
||||||
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
|
|
||||||
let dist = self.center.dot(&plane.n) - plane.d;
|
|
||||||
if dist > self.radius {
|
|
||||||
Relation::In
|
|
||||||
}else if dist < - self.radius {
|
|
||||||
Relation::Out
|
|
||||||
}else {
|
|
||||||
Relation::Cross
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ use approx::ApproxEq;
|
||||||
use matrix::*;
|
use matrix::*;
|
||||||
use num::*;
|
use num::*;
|
||||||
use point::*;
|
use point::*;
|
||||||
use ray::Ray;
|
|
||||||
use rotation::*;
|
use rotation::*;
|
||||||
use vector::*;
|
use vector::*;
|
||||||
|
|
||||||
|
@ -43,12 +42,6 @@ pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
|
||||||
/// Transform a point using this transform.
|
/// Transform a point using this transform.
|
||||||
fn transform_point(&self, point: &P) -> P;
|
fn transform_point(&self, point: &P) -> P;
|
||||||
|
|
||||||
/// Transform a ray using this transform.
|
|
||||||
#[inline]
|
|
||||||
fn transform_ray(&self, ray: &Ray<S, P,V>) -> Ray<S, P, V> {
|
|
||||||
Ray::new(self.transform_point(&ray.origin), self.transform_vector(&ray.direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transform a vector as a point using this transform.
|
/// Transform a vector as a point using this transform.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn transform_as_point(&self, vec: &V) -> V {
|
fn transform_as_point(&self, vec: &V) -> V {
|
||||||
|
|
105
tests/aabb.rs
105
tests/aabb.rs
|
@ -1,105 +0,0 @@
|
||||||
// Copyright 2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
extern crate cgmath;
|
|
||||||
|
|
||||||
use cgmath::{Aabb, Aabb2, Aabb3};
|
|
||||||
use cgmath::{Point2, Point3};
|
|
||||||
use cgmath::{Vector2, Vector3};
|
|
||||||
use cgmath::{Ray, Intersect};
|
|
||||||
use cgmath::{Plane, Bound, Relation};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_general() {
|
|
||||||
let aabb = Aabb2::new(Point2::new(-20isize, 30isize), Point2::new(10isize, -10isize));
|
|
||||||
assert_eq!(aabb.min(), &Point2::new(-20isize, -10isize));
|
|
||||||
assert_eq!(aabb.max(), &Point2::new(10isize, 30isize));
|
|
||||||
assert_eq!(aabb.dim(), Vector2::new(30isize, 40isize));
|
|
||||||
assert_eq!(aabb.volume(), 30isize * 40isize);
|
|
||||||
assert_eq!(aabb.center(), Point2::new(-5isize, 10isize));
|
|
||||||
|
|
||||||
assert!(aabb.contains(&Point2::new(0isize, 0isize)));
|
|
||||||
assert!(!aabb.contains(&Point2::new(-50isize, -50isize)));
|
|
||||||
assert!(!aabb.contains(&Point2::new(50isize, 50isize)));
|
|
||||||
|
|
||||||
assert_eq!(aabb.grow(&Point2::new(0isize, 0isize)), aabb);
|
|
||||||
assert_eq!(aabb.grow(&Point2::new(100isize, 100isize)),
|
|
||||||
Aabb2::new(Point2::new(-20isize, -10isize), Point2::new(100isize, 100isize)));
|
|
||||||
assert_eq!(aabb.grow(&Point2::new(-100isize, -100isize)),
|
|
||||||
Aabb2::new(Point2::new(-100isize, -100isize), Point2::new(10isize, 30isize)));
|
|
||||||
|
|
||||||
let aabb = Aabb3::new(Point3::new(-20isize, 30isize, 5isize), Point3::new(10isize, -10isize, -5isize));
|
|
||||||
assert_eq!(aabb.min(), &Point3::new(-20isize, -10isize, -5isize));
|
|
||||||
assert_eq!(aabb.max(), &Point3::new(10isize, 30isize, 5isize));
|
|
||||||
assert_eq!(aabb.dim(), Vector3::new(30isize, 40isize, 10isize));
|
|
||||||
assert_eq!(aabb.volume(), 30isize * 40isize * 10isize);
|
|
||||||
assert_eq!(aabb.center(), Point3::new(-5isize, 10isize, 0isize));
|
|
||||||
|
|
||||||
assert!(aabb.contains(&Point3::new(0isize, 0isize, 0isize)));
|
|
||||||
assert!(!aabb.contains(&Point3::new(-100isize, 0isize, 0isize)));
|
|
||||||
assert!(!aabb.contains(&Point3::new(100isize, 0isize, 0isize)));
|
|
||||||
assert!(aabb.contains(&Point3::new(9isize, 29isize, -1isize)));
|
|
||||||
assert!(!aabb.contains(&Point3::new(10isize, 30isize, 5isize)));
|
|
||||||
assert!(aabb.contains(&Point3::new(-20isize, -10isize, -5isize)));
|
|
||||||
assert!(!aabb.contains(&Point3::new(-21isize, -11isize, -6isize)));
|
|
||||||
|
|
||||||
assert_eq!(aabb.add_v(&Vector3::new(1isize, 2isize, 3isize)),
|
|
||||||
Aabb3::new(Point3::new(-19isize, 32isize, 8isize), Point3::new(11isize, -8isize, -2isize)));
|
|
||||||
|
|
||||||
assert_eq!(aabb.mul_s(2isize),
|
|
||||||
Aabb3::new(Point3::new(-40isize, -20isize, -10isize), Point3::new(20isize, 60isize, 10isize)));
|
|
||||||
|
|
||||||
assert_eq!(aabb.mul_v(&Vector3::new(1isize, 2isize, 3isize)),
|
|
||||||
Aabb3::new(Point3::new(-20isize, -20isize, -15isize), Point3::new(10isize, 60isize, 15isize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ray_intersect() {
|
|
||||||
let aabb = Aabb2::new(Point2::new(-5.0f32, 5.0), Point2::new(5.0, 10.0));
|
|
||||||
let ray1 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(0.0, 1.0));
|
|
||||||
let ray2 = Ray::new(Point2::new(-10.0f32, 0.0), Vector2::new(2.5, 1.0));
|
|
||||||
let ray3 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(-1.0, -1.0));
|
|
||||||
let ray4 = Ray::new(Point2::new(3.0f32, 7.0), Vector2::new(1.0, 1.0));
|
|
||||||
|
|
||||||
assert_eq!((ray1, aabb).intersection(), Some(Point2::new(0.0, 5.0)));
|
|
||||||
assert_eq!((ray2, aabb).intersection(), Some(Point2::new(2.5, 5.0)));
|
|
||||||
assert_eq!((ray3, aabb).intersection(), None);
|
|
||||||
assert_eq!((ray4, aabb).intersection(), Some(Point2::new(5.0, 9.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_corners() {
|
|
||||||
let corners = Aabb2::new(Point2::new(-5.0f32, 5.0), Point2::new(5.0, 10.0))
|
|
||||||
.to_corners();
|
|
||||||
assert!(corners.contains(&Point2::new(-5f32, 10.0)));
|
|
||||||
assert!(corners.contains(&Point2::new(5f32, 5.0)));
|
|
||||||
|
|
||||||
let corners = Aabb3::new(Point3::new(-20isize, 30isize, 5isize), Point3::new(10isize, -10isize, -5isize))
|
|
||||||
.to_corners();
|
|
||||||
assert!(corners.contains(&Point3::new(-20isize, 30isize, -5isize)));
|
|
||||||
assert!(corners.contains(&Point3::new(10isize, 30isize, 5isize)));
|
|
||||||
assert!(corners.contains(&Point3::new(10isize, -10isize, 5isize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bound() {
|
|
||||||
let aabb = Aabb3::new(Point3::new(-5.0f32, 5.0, 0.0), Point3::new(5.0, 10.0, 1.0));
|
|
||||||
let plane1 = Plane::from_point_normal(Point3::new(0f32, 0.0, 0.0), Vector3::new(0f32, 0.0, 1.0));
|
|
||||||
let plane2 = Plane::from_point_normal(Point3::new(-5.0f32, 4.0, 0.0), Vector3::new(0f32, 1.0, 0.0));
|
|
||||||
let plane3 = Plane::from_point_normal(Point3::new(6.0f32, 0.0, 0.0), Vector3::new(1f32, 0.0, 0.0));
|
|
||||||
assert_eq!(aabb.relate_plane(&plane1), Relation::Cross);
|
|
||||||
assert_eq!(aabb.relate_plane(&plane2), Relation::In);
|
|
||||||
assert_eq!(aabb.relate_plane(&plane3), Relation::Out);
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright 2015 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.
|
|
||||||
|
|
||||||
extern crate cgmath;
|
|
||||||
|
|
||||||
use cgmath::{PerspectiveFov, Point3, Projection, Relation, Sphere, rad};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_contains() {
|
|
||||||
let frustum = PerspectiveFov {
|
|
||||||
fovy: rad(1f32),
|
|
||||||
aspect: 1f32,
|
|
||||||
near: 1f32,
|
|
||||||
far: 10f32,
|
|
||||||
}.to_frustum();
|
|
||||||
assert_eq!(frustum.contains(&Sphere {
|
|
||||||
center: Point3::new(0f32, 0f32, -5f32),
|
|
||||||
radius: 1f32,
|
|
||||||
}), Relation::In);
|
|
||||||
assert_eq!(frustum.contains(&Sphere {
|
|
||||||
center: Point3::new(0f32, 3f32, -5f32),
|
|
||||||
radius: 1f32,
|
|
||||||
}), Relation::Cross);
|
|
||||||
assert_eq!(frustum.contains(&Sphere {
|
|
||||||
center: Point3::new(0f32, 0f32, 5f32),
|
|
||||||
radius: 1f32,
|
|
||||||
}), Relation::Out);
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
|
|
||||||
extern crate cgmath;
|
|
||||||
|
|
||||||
use cgmath::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_line_intersection() {
|
|
||||||
// collinear, intersection is line dest
|
|
||||||
let r1 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(0.25, 0.0));
|
|
||||||
let l1 = Line::new(Point2::new(1.5f32, 0.0), Point2::new(0.5, 0.0));
|
|
||||||
assert_eq!((r1, l1).intersection(), Some(Point2::new(0.5, 0.0)));
|
|
||||||
|
|
||||||
// collinear, intersection is at ray origin
|
|
||||||
let r2 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(5.0, 0.0));
|
|
||||||
let l2 = Line::new(Point2::new(-11.0f32, 0.0), Point2::new(1.0, 0.0));
|
|
||||||
assert_eq!((r2, l2).intersection(), Some(Point2::new(0.0, 0.0)));
|
|
||||||
|
|
||||||
// collinear, intersection is line origin
|
|
||||||
let r3 = Ray::new(Point2::new(0.0f32, 1.0), Vector2::new(0.0, -0.25));
|
|
||||||
let l3 = Line::new(Point2::new(0.0f32, 0.5), Point2::new(0.0, -0.5));
|
|
||||||
assert_eq!((r3, l3).intersection(), Some(Point2::new(0.0, 0.5)));
|
|
||||||
|
|
||||||
// collinear, no overlap
|
|
||||||
let r4 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(3.0, 0.0));
|
|
||||||
let l4 = Line::new(Point2::new(-10.0f32, 0.0), Point2::new(-5.0, 0.0));
|
|
||||||
assert_eq!((r4, l4).intersection(), None);
|
|
||||||
|
|
||||||
// no intersection
|
|
||||||
let r5 = Ray::new(Point2::new(5.0f32, 5.0), Vector2::new(40.0, 8.0));
|
|
||||||
let l5 = Line::new(Point2::new(5.0f32, 4.8), Point2::new(10.0, 4.1));
|
|
||||||
assert_eq!((r5, l5).intersection(), None); // no intersection
|
|
||||||
|
|
||||||
// non-collinear intersection
|
|
||||||
let r6 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(10.0, 10.0));
|
|
||||||
let l6 = Line::new(Point2::new(0.0f32, 10.0), Point2::new(10.0, 0.0));
|
|
||||||
assert_eq!((r6, l6).intersection(), Some(Point2::new(5.0, 5.0)));
|
|
||||||
|
|
||||||
// line is a point that does not intersect
|
|
||||||
let r7 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 1.0));
|
|
||||||
let l7 = Line::new(Point2::new(1.0f32, 0.0), Point2::new(1.0, 0.0));
|
|
||||||
assert_eq!((r7, l7).intersection(), None);
|
|
||||||
|
|
||||||
// line is a point that does intersect
|
|
||||||
let r8 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 0.0));
|
|
||||||
let l8 = Line::new(Point2::new(3.0f32, 0.0), Point2::new(3.0, 0.0));
|
|
||||||
assert_eq!((r8, l8).intersection(), Some(Point2::new(3.0, 0.0)));
|
|
||||||
|
|
||||||
// line is a collinear point but no intersection
|
|
||||||
let r9 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 0.0));
|
|
||||||
let l9 = Line::new(Point2::new(-1.0f32, 0.0), Point2::new(-1.0, 0.0));
|
|
||||||
assert_eq!((r9, l9).intersection(), None);
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
|
|
||||||
extern crate cgmath;
|
|
||||||
|
|
||||||
use cgmath::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_points() {
|
|
||||||
assert_eq!(Plane::from_points(Point3::new(5.0f64, 0.0f64, 5.0f64),
|
|
||||||
Point3::new(5.0f64, 5.0f64, 5.0f64),
|
|
||||||
Point3::new(5.0f64, 0.0f64, -1.0f64)),
|
|
||||||
Some(Plane::from_abcd(-1.0f64, 0.0f64, 0.0f64, 5.0f64)));
|
|
||||||
|
|
||||||
assert_eq!(Plane::from_points(Point3::new(0.0f64, 5.0f64, -5.0f64),
|
|
||||||
Point3::new(0.0f64, 5.0f64, 0.0f64),
|
|
||||||
Point3::new(0.0f64, 5.0f64, 5.0f64)),
|
|
||||||
None); // The points are parallel
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ray_intersection() {
|
|
||||||
let p0 = Plane::from_abcd(1f64, 0f64, 0f64, -7f64);
|
|
||||||
let r0: Ray3<f64> = Ray::new(Point3::new(2f64, 3f64, 4f64), Vector3::new(1f64, 1f64, 1f64).normalize());
|
|
||||||
assert_eq!((p0, r0).intersection(), Some(Point3::new(7f64, 8f64, 9f64)));
|
|
||||||
|
|
||||||
let p1 = Plane::from_points(Point3::new(5f64, 0f64, 5f64),
|
|
||||||
Point3::new(5f64, 5f64, 5f64),
|
|
||||||
Point3::new(5f64, 0f64, -1f64)).unwrap();
|
|
||||||
let r1: Ray3<f64> = Ray::new(Point3::new(0f64, 0f64, 0f64), Vector3::new(-1f64, 0f64, 0f64).normalize());
|
|
||||||
assert_eq!((p1, r1).intersection(), None); // r1 points away from p1
|
|
||||||
}
|
|
|
@ -16,23 +16,11 @@
|
||||||
|
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
|
|
||||||
use cgmath::{Point, Point3, Vector, Vector3};
|
use cgmath::Point3;
|
||||||
use cgmath::{Bound, Relation, Plane};
|
use cgmath::ApproxEq;
|
||||||
use cgmath::{ApproxEq};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_homogeneous() {
|
fn test_homogeneous() {
|
||||||
let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
|
let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
|
||||||
assert!(p.approx_eq(&Point3::from_homogeneous(&p.to_homogeneous())));
|
assert!(p.approx_eq(&Point3::from_homogeneous(&p.to_homogeneous())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bound() {
|
|
||||||
let point = Point3::new(1f32, 2.0, 3.0);
|
|
||||||
let normal = Vector3::new(0f32, -0.8, -0.36);
|
|
||||||
let plane = Plane::from_point_normal(point, normal);
|
|
||||||
|
|
||||||
assert_eq!(point.relate_plane(&plane), Relation::Cross);
|
|
||||||
assert_eq!(point.add_v(&normal).relate_plane(&plane), Relation::In);
|
|
||||||
assert_eq!(point.add_v(&normal.mul_s(-1.0)).relate_plane(&plane), Relation::Out);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright 2014 The CGMath Developers. For a full listing of the authors,
|
|
||||||
// refer to the Cargo.toml 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.
|
|
||||||
|
|
||||||
|
|
||||||
extern crate cgmath;
|
|
||||||
|
|
||||||
use cgmath::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_intersection() {
|
|
||||||
let sphere = Sphere {center: Point3::new(0f64,0f64,0f64), radius: 1f64};
|
|
||||||
let r0 = Ray::new(Point3::new(0f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
|
|
||||||
let r1 = Ray::new(Point3::new(1f64.cos(), 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
|
|
||||||
let r2 = Ray::new(Point3::new(1f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
|
|
||||||
let r3 = Ray::new(Point3::new(2f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
|
|
||||||
assert_eq!((sphere,r0).intersection(), Some(Point3::new(0f64, 0f64, 1f64)));
|
|
||||||
assert!((sphere,r1).intersection().unwrap().approx_eq( &Point3::new(1f64.cos(), 0f64, 1f64.sin()) ));
|
|
||||||
assert_eq!((sphere,r2).intersection(), Some(Point3::new(1f64, 0f64, 0f64)));
|
|
||||||
assert_eq!((sphere,r3).intersection(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bound() {
|
|
||||||
let point = Point3::new(1f32, 2.0, 3.0);
|
|
||||||
let sphere = Sphere { center: point, radius: 1.0 };
|
|
||||||
let normal = vec3(0f32, 0.0, 1.0);
|
|
||||||
|
|
||||||
assert_eq!(sphere.relate_plane(
|
|
||||||
&Plane::from_point_normal(point, normal)
|
|
||||||
), Relation::Cross);
|
|
||||||
assert_eq!(sphere.relate_plane(
|
|
||||||
&Plane::from_point_normal(point.add_v(&normal.mul_s(-3.0)), normal),
|
|
||||||
), Relation::In);
|
|
||||||
assert_eq!(sphere.relate_plane(
|
|
||||||
&Plane::from_point_normal(point.add_v(&normal.mul_s(3.0)), normal),
|
|
||||||
), Relation::Out);
|
|
||||||
}
|
|
Loading…
Reference in a new issue