| // 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; |
| }; |
| |