<commit_before>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/Cartesian3',
        '../Core/Cartographic',
        '../Core/DeveloperError',
        '../Core/Ellipsoid',
        '../Core/HermiteSpline',
        '../Core/Math',
        '../Core/Matrix3',
        '../Core/OrientationInterpolator',
        '../Core/Quaternion',
        '../ThirdParty/Tween'
    ], function(
        defaultValue,
        Cartesian3,
        Cartographic,
        DeveloperError,
        Ellipsoid,
        HermiteSpline,
        CesiumMath,
        Matrix3,
        OrientationInterpolator,
        Quaternion,
        Tween) {
    "use strict";

    var CameraFlightPath = {
    };

    function createQuaternion(direction, up) {
        var right = direction.cross(up);
        var viewMat = new Matrix3( right.x,      right.y,      right.z,
                                   up.x,         up.y,         up.z,
                                  -direction.x, -direction.y, -direction.z);
        return Quaternion.fromRotationMatrix(viewMat);
    }

    CameraFlightPath.createAnimation = function(camera, destination, ellipsoid, duration, onComplete) {
        if (typeof camera === 'undefined') {
            throw new DeveloperError('camera is required.');
        }

        if (typeof destination === 'undefined') {
            throw new DeveloperError('destination is required.');
        }

        ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
        duration = defaultValue(duration, 3000.0);

        var start = camera.position;
        var end = ellipsoid.cartographicToCartesian(destination);
        var startCart = ellipsoid.cartesianToCartographic(start);

        var halfDistance = start.subtract(end).magnitude() * 0.5;

        var midCart = new Cartographic();
        midCart.longitude = CesiumMath.lerp(startCart.longitude, destination.longitude, 0.25);
        midCart.latitude = CesiumMath.lerp(startCart.latitude, destination.latitude, 0.25);
        midCart.height = halfDistance;
        var mid0 = ellipsoid.cartographicToCartesian(midCart);
        midCart.longitude = CesiumMath.lerp(startCart.longitude, destination.longitude, 0.75);
        midCart.latitude = CesiumMath.lerp(startCart.latitude, destination.latitude, 0.75);
        midCart.height = halfDistance;
        var mid1 = ellipsoid.cartographicToCartesian(midCart);

        var points = [
            {
                point : start,
                time : 0.0
            },
            {
                point : mid0,
                time : 0.25
            },
            {
                point : mid1,
                time : 0.75
            },
            {
                point : end,
                time : 1.0
            }
        ];
        var path = new HermiteSpline(points);

        var direction = end.negate().normalize();
        var up = direction.cross(points[3].tangent).normalize();
        var orientationControlPoints = [
            {
                orientation : createQuaternion(camera.direction, camera.up),
                time : 0.0
            },
            {
                orientation : createQuaternion(direction, up),
                time : 1.0
            }
        ];
        var orientations = new OrientationInterpolator(orientationControlPoints);

        var update = function(value) {
            var time = value.time;
            var orientation = orientations.evaluate(time);
            var rotationMatrix = Matrix3.fromQuaternion(orientation);

            camera.position = path.evaluate(time);
            camera.right = rotationMatrix.getColumn(0);
            camera.up = rotationMatrix.getColumn(1);
            camera.direction = rotationMatrix.getColumn(2).negate();
        };

        return {
            duration : duration,
            easingFunction : Tween.Easing.Cubic.EaseInOut,
            startValue : {
                time : 0.0
            },
            stopValue : {
                time : 1.0<commit_msg>Re-use some of the code from the old flight controller to create better paths.<commit_after>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/Cartesian3',
        '../Core/Cartographic',
        '../Core/DeveloperError',
        '../Core/Ellipsoid',
        '../Core/HermiteSpline',
        '../Core/Math',
        '../Core/Matrix3',
        '../Core/OrientationInterpolator',
        '../Core/Quaternion',
        '../ThirdParty/Tween'
    ], function(
        defaultValue,
        Cartesian3,
        Cartographic,
        DeveloperError,
        Ellipsoid,
        HermiteSpline,
        CesiumMath,
        Matrix3,
        OrientationInterpolator,
        Quaternion,
        Tween) {
    "use strict";

    var CameraFlightPath = {
    };

    function createQuaternion(direction, up) {
        var right = direction.cross(up);
        var viewMat = new Matrix3( right.x,      right.y,      right.z,
                                   up.x,         up.y,         up.z,
                                  -direction.x, -direction.y, -direction.z);
        return Quaternion.fromRotationMatrix(viewMat);
    }

    function createPath(camera, ellipsoid, end, duration) {
        var start = camera.position;

        // get minimum altitude from which the whole ellipsoid is visible
        var radius = ellipsoid.getMaximumRadius();

        var frustum = camera.frustum;
        var near = frustum.near;
        var top = frustum.near * Math.tan(0.5 * frustum.fovy);
        var right = frustum.aspectRatio * top;

        var dx = radius * near / right;
        var dy = radius * near / top;
        var maxStartAlt = Math.max(dx, dy);

        var dot = start.normalize().dot(end.normalize());

        var abovePercentage, incrementPercentage;
        var startAboveMaxAlt = (start.magnitude() > maxStartAlt);
        if (startAboveMaxAlt) {
            abovePercentage = 0.6;
            incrementPercentage = 0.35;
        } else {
            abovePercentage = Math.max(0.1, 1.0 - Math.abs(dot));
            incrementPercentage = 0.5;
        }

        maxStartAlt = radius + abovePercentage * (maxStartAlt - radius);

        var aboveEnd = end.normalize().multiplyByScalar(maxStartAlt);
        var afterStart = start.normalize().multiplyByScalar(maxStartAlt);

        var points, axis, angle, rotation;
        if (start.magnitude() > maxStartAlt && dot > 0) {
            var middle = start.subtract(aboveEnd).multiplyByScalar(0.5).add(aboveEnd);

            points = [{
                point : start
            }, {
                point : middle
            }, {
                point : end
            }];
        } else {
            points = [{
                point : start
            }];

            angle = Math.acos(afterStart.normalize().dot(aboveEnd.normalize()));
            axis = aboveEnd.cross(afterStart);

            var increment = incrementPercentage * angle;
            var startCondition = angle - increment;
            for ( var i = startCondition; i > 0.0; i = i - increment) {
                rotation = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(axis, i));
                points.push({
                    point : rotation.multiplyByVector(aboveEnd)
                });
            }

            points.push({
                point : end
            });
        }

        var scalar = duration / (points.length - 1);
        for ( var k = 0; k < points.length; ++k) {
            points[k].time = k * scalar;
        }

        return new HermiteSpline(points);
    }

    function createOrientations(camera, end, duration) {
        var direction = end.negate().normalize();
        var right = direction.cross(Cartesian3.UNIT_Z).normalize();
        var up = right.cross(direction);
        var orientationControlPoints = [
            {
                orientation : createQuaternion(camera.direction, camera.up),
                time : 0.0
            },
            {
                orientation : createQuaternion(direction, up),
                time : duration
            }
        ];
        return new OrientationInterpolator(orientationControlPoints);
    }

    CameraFlightPath.createAnimation = function(camera, destination, ellipsoid, duration, onComplete) {
        if (typeof camera === 'undefined') {
            throw new DeveloperError('camera is required.');
        }

        if (typeof destination === 'undefined') {
            throw new DeveloperError('destination is required.');
        }

        ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
        duration = defaultValue(duration, 3000.0);
        var end = ellipsoid.cartographicToCartesian(destination);

        var path = createPath(camera, ellipsoid, end, duration);
        var orientations = createOrientations(camera, end, duration);

        var update = function(value) {
            var time = value.time;
            var orientation = orientations.evaluate(time);
            var rotationMatrix = Matrix3.fromQuaternion(orientation);

            camera.position = path.evaluate(time);
            camera.right = rotationMatrix.getColumn(0);
            camera.up = rotationMatrix.getColumn(1);
            camera.direction = rotationMatrix.getColumn(2).negate();

            /*
            camera.position = path.evaluate(time);
            camera.direction = camera.position.negate().normalize();
            camera.right = camera.direction.cross(Cartesian3.UNIT_Z).normalize();
            camera.up = camera.position.cross(camera.right).normalize();
            camera.right = camera.direction.cross(camera.up);
            */
        };

        return {
            duration : duration,
            easingFunction : Tween.Easing.Cubic.EaseInOut,
            startValue : {
                time : 0.0
            },
            stopValue : {
                time : duration
{'fraction_non_alphanumeric': 0.10906142306912629, 'fraction_numerical': 0.009730387188323536, 'mean_word_length': 1.6776119402985075, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5302186', 'n_tokens_mistral': 2753, 'n_tokens_neox': 2604, 'n_words': 531}