blob: be07926a6e859ac34ec5c8579d29619049d96d28 [file] [log] [blame]
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
part of vector_math;
/// Defines a [Ray] by an [origin] and a [direction].
class Ray {
final Vector3 _origin;
final Vector3 _direction;
/// The [origin] of the ray.
Vector3 get origin => _origin;
/// The [direction] of the ray.
Vector3 get direction => _direction;
/// Create a new, uninitialized ray.
Ray()
: _origin = new Vector3.zero(),
_direction = new Vector3.zero();
/// Create a ray as a copy of [other].
Ray.copy(Ray other)
: _origin = new Vector3.copy(other._origin),
_direction = new Vector3.copy(other._direction);
/// Create a ray with an [origin] and a [direction].
Ray.originDirection(Vector3 origin, Vector3 direction)
: _origin = new Vector3.copy(origin),
_direction = new Vector3.copy(direction);
/// Copy the [origin] and [direction] from [other] into [this].
void copyFrom(Ray other) {
_origin.setFrom(other._origin);
_direction.setFrom(other._direction);
}
/// Returns the position on [this] with a distance of [t] from [origin].
Vector3 at(double t) => _direction.scaled(t)..add(_origin);
/// Copy the position on [this] with a distance of [t] from [origin] into
/// [other].
void copyAt(Vector3 other, double t) {
other
..setFrom(_direction)
..scale(t)
..add(_origin);
}
/// Return the distance from the origin of [this] to the intersection with
/// [other] if [this] intersects with [other], or null if the don't intersect.
double intersectsWithSphere(Sphere other) {
final double r = other._radius;
final double r2 = r * r;
final Vector3 l = other._center.clone()..sub(_origin);
final double s = l.dot(_direction);
final double l2 = l.dot(l);
if (s < 0 && l2 > r2) {
return null;
}
final double m2 = l2 - s * s;
if (m2 > r2) {
return null;
}
final double q = Math.sqrt(r2 - m2);
return (l2 > r2) ? s - q : s + q;
}
// Some varaibles that are used for intersectsWithTriangle and
// intersectsWithQuad. The performance is better in Dart and JS if we avoid
// to create temporary instance over and over. Also reduce GC.
static final Vector3 _e1 = new Vector3.zero();
static final Vector3 _e2 = new Vector3.zero();
static final Vector3 _q = new Vector3.zero();
static final Vector3 _s = new Vector3.zero();
static final Vector3 _r = new Vector3.zero();
/// Return the distance from the origin of [this] to the intersection with
/// [other] if [this] intersects with [other], or null if the don't intersect.
double intersectsWithTriangle(Triangle other) {
const double EPSILON = 10e-6;
final Vector3 point0 = other._point0;
final Vector3 point1 = other._point1;
final Vector3 point2 = other._point2;
_e1
..setFrom(point1)
..sub(point0);
_e2
..setFrom(point2)
..sub(point0);
_direction.crossInto(_e2, _q);
final double a = _e1.dot(_q);
if (a > -EPSILON && a < EPSILON) {
return null;
}
final double f = 1 / a;
_s
..setFrom(_origin)
..sub(point0);
final double u = f * (_s.dot(_q));
if (u < 0.0) {
return null;
}
_s.crossInto(_e1, _r);
final double v = f * (_direction.dot(_r));
if (v < -EPSILON || u + v > 1.0 + EPSILON) {
return null;
}
final double t = f * (_e2.dot(_r));
return t;
}
/// Return the distance from the origin of [this] to the intersection with
/// [other] if [this] intersects with [other], or null if the don't intersect.
double intersectsWithQuad(Quad other) {
const double EPSILON = 10e-6;
// First triangle
Vector3 point0 = other._point0;
Vector3 point1 = other._point1;
Vector3 point2 = other._point2;
_e1
..setFrom(point1)
..sub(point0);
_e2
..setFrom(point2)
..sub(point0);
_direction.crossInto(_e2, _q);
final double a0 = _e1.dot(_q);
if (!(a0 > -EPSILON && a0 < EPSILON)) {
final double f = 1 / a0;
_s
..setFrom(_origin)
..sub(point0);
final double u = f * (_s.dot(_q));
if (u >= 0.0) {
_s.crossInto(_e1, _r);
final double v = f * (_direction.dot(_r));
if (!(v < -EPSILON || u + v > 1.0 + EPSILON)) {
final double t = f * (_e2.dot(_r));
return t;
}
}
}
// Second triangle
point0 = other._point3;
point1 = other._point0;
point2 = other._point2;
_e1
..setFrom(point1)
..sub(point0);
_e2
..setFrom(point2)
..sub(point0);
_direction.crossInto(_e2, _q);
final double a1 = _e1.dot(_q);
if (!(a1 > -EPSILON && a1 < EPSILON)) {
final double f = 1 / a1;
_s
..setFrom(_origin)
..sub(point0);
final double u = f * (_s.dot(_q));
if (u >= 0.0) {
_s.crossInto(_e1, _r);
final double v = f * (_direction.dot(_r));
if (!(v < -EPSILON || u + v > 1.0 + EPSILON)) {
final double t = f * (_e2.dot(_r));
return t;
}
}
}
return null;
}
/// Return the distance from the origin of [this] to the intersection with
/// [other] if [this] intersects with [other], or null if the don't intersect.
double intersectsWithAabb3(Aabb3 other) {
final Vector3 otherMin = other.min;
final Vector3 otherMax = other.max;
double tNear = -double.MAX_FINITE;
double tFar = double.MAX_FINITE;
for (int i = 0; i < 3; ++i) {
if (_direction[i] == 0.0) {
if (_origin[i] < otherMin[i] || _origin[i] > otherMax[i]) {
return null;
}
} else {
double t1 = (otherMin[i] - _origin[i]) / _direction[i];
double t2 = (otherMax[i] - _origin[i]) / _direction[i];
if (t1 > t2) {
final double temp = t1;
t1 = t2;
t2 = temp;
}
if (t1 > tNear) {
tNear = t1;
}
if (t2 < tFar) {
tFar = t2;
}
if (tNear > tFar || tFar < 0) {
return null;
}
}
}
return tNear;
}
}