import { Vector3 } from './Vector3.js';
var _vec3_1 = new Vector3();
var _diff = new Vector3();
var _edge1 = new Vector3();
var _edge2 = new Vector3();
var _normal = new Vector3();
/**
* @constructor
* @memberof zen3d
* @param {zen3d.Vector3} [origin=]
* @param {zen3d.Vector3} [direction=]
*/
function Ray(origin, direction) {
this.origin = (origin !== undefined) ? origin : new Vector3();
this.direction = (direction !== undefined) ? direction : new Vector3();
}
Object.assign(Ray.prototype, /** @lends zen3d.Ray.prototype */{
/**
*
*/
set: function(origin, direction) {
this.origin.copy(origin);
this.direction.copy(direction);
},
/**
*
*/
at: function(t, optionalTarget) {
var result = optionalTarget || new Vector3();
return result.copy(this.direction).multiplyScalar(t).add(this.origin);
},
/**
* @method
*/
intersectsSphere: function(sphere, optionalTarget) {
_vec3_1.subVectors(sphere.center, this.origin);
var tca = _vec3_1.dot(this.direction);
var d2 = _vec3_1.dot(_vec3_1) - tca * tca;
var radius2 = sphere.radius * sphere.radius;
if (d2 > radius2) {
return null;
}
var thc = Math.sqrt(radius2 - d2);
// t0 = first intersect point - entrance on front of sphere
var t0 = tca - thc;
// t1 = second intersect point - exit point on back of sphere
var t1 = tca + thc;
// console.log(t0, t1);
// test to see if both t0 and t1 are behind the ray - if so, return null
if (t0 < 0 && t1 < 0) {
return null;
}
// test to see if t0 is behind the ray:
// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
// in order to always return an intersect point that is in front of the ray.
if (t0 < 0) {
return this.at(t1, optionalTarget);
}
// else t0 is in front of the ray, so return the first collision point scaled by t0
return this.at(t0, optionalTarget);
},
/**
*
*/
intersectsBox: function(box, optionalTarget) {
var tmin, tmax, tymin, tymax, tzmin, tzmax;
var invdirx = 1 / this.direction.x,
invdiry = 1 / this.direction.y,
invdirz = 1 / this.direction.z;
var origin = this.origin;
if (invdirx >= 0) {
tmin = (box.min.x - origin.x) * invdirx;
tmax = (box.max.x - origin.x) * invdirx;
} else {
tmin = (box.max.x - origin.x) * invdirx;
tmax = (box.min.x - origin.x) * invdirx;
}
if (invdiry >= 0) {
tymin = (box.min.y - origin.y) * invdiry;
tymax = (box.max.y - origin.y) * invdiry;
} else {
tymin = (box.max.y - origin.y) * invdiry;
tymax = (box.min.y - origin.y) * invdiry;
}
if ((tmin > tymax) || (tymin > tmax)) return null;
// These lines also handle the case where tmin or tmax is NaN
// (result of 0 * Infinity). x !== x returns true if x is NaN
if (tymin > tmin || tmin !== tmin) tmin = tymin;
if (tymax < tmax || tmax !== tmax) tmax = tymax;
if (invdirz >= 0) {
tzmin = (box.min.z - origin.z) * invdirz;
tzmax = (box.max.z - origin.z) * invdirz;
} else {
tzmin = (box.max.z - origin.z) * invdirz;
tzmax = (box.min.z - origin.z) * invdirz;
}
if ((tmin > tzmax) || (tzmin > tmax)) return null;
if (tzmin > tmin || tmin !== tmin) tmin = tzmin;
if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
// return point closest to the ray (positive side)
if (tmax < 0) return null;
return this.at(tmin >= 0 ? tmin : tmax, optionalTarget);
},
/**
* @method
*/
intersectTriangle: function(a, b, c, backfaceCulling, optionalTarget) {
// Compute the offset origin, edges, and normal.
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
_edge1.subVectors(b, a);
_edge2.subVectors(c, a);
_normal.crossVectors(_edge1, _edge2);
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
var DdN = this.direction.dot(_normal);
var sign;
if (DdN > 0) {
if (backfaceCulling) return null;
sign = 1;
} else if (DdN < 0) {
sign = -1;
DdN = -DdN;
} else {
return null;
}
_diff.subVectors(this.origin, a);
var DdQxE2 = sign * this.direction.dot(_edge2.crossVectors(_diff, _edge2));
// b1 < 0, no intersection
if (DdQxE2 < 0) {
return null;
}
var DdE1xQ = sign * this.direction.dot(_edge1.cross(_diff));
// b2 < 0, no intersection
if (DdE1xQ < 0) {
return null;
}
// b1+b2 > 1, no intersection
if (DdQxE2 + DdE1xQ > DdN) {
return null;
}
// Line intersects triangle, check if ray does.
var QdN = -sign * _diff.dot(_normal);
// t < 0, no intersection
if (QdN < 0) {
return null;
}
// Ray intersects triangle.
return this.at(QdN / DdN, optionalTarget);
},
/**
*
*/
copy: function(ray) {
this.origin.copy(ray.origin);
this.direction.copy(ray.direction);
return this;
},
/**
*
*/
applyMatrix4: function(matrix4) {
this.direction.add(this.origin).applyMatrix4(matrix4);
this.origin.applyMatrix4(matrix4);
this.direction.sub(this.origin);
this.direction.normalize();
return this;
}
});
export { Ray };