blob: f196858fcc519621ac9307db7d7150b5fb26d2bf [file] [log] [blame]
// Copyright (c) 2001-2010, Purdue University. All rights reserved.
// Copyright (C) 2015 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Purdue University nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function Motion(callsign, posOne, posTwo) {
this.callsign = callsign;
this.posOne = posOne;
this.posTwo = posTwo;
}
Motion.prototype.toString = function() {
return "Motion(" + this.callsign + " from " + this.posOne + " to " + this.posTwo + ")";
};
Motion.prototype.delta = function() {
return this.posTwo.minus(this.posOne);
};
Motion.prototype.findIntersection = function(other) {
var init1 = this.posOne;
var init2 = other.posOne;
var vec1 = this.delta();
var vec2 = other.delta();
var radius = Constants.PROXIMITY_RADIUS;
// this test is not geometrical 3-d intersection test, it takes the fact that the aircraft move
// into account ; so it is more like a 4d test
// (it assumes that both of the aircraft have a constant speed over the tested interval)
// we thus have two points, each of them moving on its line segment at constant speed ; we are looking
// for times when the distance between these two points is smaller than r
// vec1 is vector of aircraft 1
// vec2 is vector of aircraft 2
// a = (V2 - V1)^T * (V2 - V1)
var a = vec2.minus(vec1).squaredMagnitude();
if (a != 0) {
// we are first looking for instances of time when the planes are exactly r from each other
// at least one plane is moving ; if the planes are moving in parallel, they do not have constant speed
// if the planes are moving in parallel, then
// if the faster starts behind the slower, we can have 2, 1, or 0 solutions
// if the faster plane starts in front of the slower, we can have 0 or 1 solutions
// if the planes are not moving in parallel, then
// point P1 = I1 + vV1
// point P2 = I2 + vV2
// - looking for v, such that dist(P1,P2) = || P1 - P2 || = r
// it follows that || P1 - P2 || = sqrt( < P1-P2, P1-P2 > )
// 0 = -r^2 + < P1 - P2, P1 - P2 >
// from properties of dot product
// 0 = -r^2 + <I1-I2,I1-I2> + v * 2<I1-I2, V1-V2> + v^2 *<V1-V2,V1-V2>
// so we calculate a, b, c - and solve the quadratic equation
// 0 = c + bv + av^2
// b = 2 * <I1-I2, V1-V2>
var b = 2 * init1.minus(init2).dot(vec1.minus(vec2));
// c = -r^2 + (I2 - I1)^T * (I2 - I1)
var c = -radius * radius + init2.minus(init1).squaredMagnitude();
var discr = b * b - 4 * a * c;
if (discr < 0)
return null;
var v1 = (-b - Math.sqrt(discr)) / (2 * a);
var v2 = (-b + Math.sqrt(discr)) / (2 * a);
if (v1 <= v2 && ((v1 <= 1 && 1 <= v2) ||
(v1 <= 0 && 0 <= v2) ||
(0 <= v1 && v2 <= 1))) {
// Pick a good "time" at which to report the collision.
var v;
if (v1 <= 0) {
// The collision started before this frame. Report it at the start of the frame.
v = 0;
} else {
// The collision started during this frame. Report it at that moment.
v = v1;
}
var result1 = init1.plus(vec1.times(v));
var result2 = init2.plus(vec2.times(v));
var result = result1.plus(result2).times(0.5);
if (result.x >= Constants.MIN_X &&
result.x <= Constants.MAX_X &&
result.y >= Constants.MIN_Y &&
result.y <= Constants.MAX_Y &&
result.z >= Constants.MIN_Z &&
result.z <= Constants.MAX_Z)
return result;
}
return null;
}
// the planes have the same speeds and are moving in parallel (or they are not moving at all)
// they thus have the same distance all the time ; we calculate it from the initial point
// dist = || i2 - i1 || = sqrt( ( i2 - i1 )^T * ( i2 - i1 ) )
var dist = init2.minus(init1).magnitude();
if (dist <= radius)
return init1.plus(init2).times(0.5);
return null;
};