// 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 + + v * 2 + v^2 * // so we calculate a, b, c - and solve the quadratic equation // 0 = c + bv + av^2 // b = 2 * 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; };