<commit_before>/// <reference path="build/jquery" />
/// <reference path="build/three" />

/// <reference path="antigenic-map-viewer.d.ts" />

import AmvUtils = require("amv-utils");
import AmvLevel1 = require("amv-level1");
import AcmacsPlotData = require("acmacs-plot-data");
import AmvManipulator = require("amv-manipulator");
import AmvManipulator2d = require("amv-manipulator-2d");

// ----------------------------------------------------------------------

export class Viewer extends AmvLevel1.Viewer
{
    public static camera_up = new THREE.Vector3(0, 1, 0);
    private static s_maximum_drawing_order :number = 1000;

    private grid :Grid;
    private maximum_drawing_order :number;
    private viewport_initial :AcmacsPlotData.Viewport; // for reset

    private rotate_control :AmvManipulator2d.RotateControl;
    private fliph_control :AmvManipulator2d.FlipControl;
    private flipv_control :AmvManipulator2d.FlipControl;
    private zoom_control :AmvManipulator2d.ZoomControl;
    private scale_control :AmvManipulator2d.ScaleControl;
    private pan_control :AmvManipulator2d.PanControl;
    private key_control :AmvManipulator2d.KeyControl;
    private hover_control :AmvManipulator2d.HoverControl;

    constructor(widget :AmvLevel1.MapWidgetLevel1) {
        super(widget);
        this.maximum_drawing_order = Viewer.s_maximum_drawing_order;
        this.viewport_initial = null;
        this.camera = new THREE.OrthographicCamera(0, 1, 1, 0, 0, this.maximum_drawing_order + 2);
        widget.add(this.camera);
        this.grid = new Grid(this, 0);
        this.reset()
    }

    // collects current state of the viewer: transformation matrix and viewport
    public state() :void {
        var transformation = this.transformation();
        console.log('transformation', JSON.stringify(transformation));
        var viewport = this.viewport();
    }

    public reset() :void {
        this.widget.reset_objects();
        this.camera.up.copy(Viewer.camera_up);
        this.camera.position.set(0, 0, this.maximum_drawing_order + 1);
        this.camera_look_at(AmvLevel1.Viewer.const_vector3_zero);
        this.viewport(this.viewport_initial);
        this.camera_update();
    }

    public viewport(viewport? :AcmacsPlotData.Viewport) :AcmacsPlotData.Viewport {
        var camera = <THREE.OrthographicCamera>this.camera;
        if (!!viewport) {
            var hsize = viewport.size / 2;
            camera.left = viewport.cx - hsize;
            camera.right = viewport.cx + hsize;
            camera.top = viewport.cy + hsize;
            camera.bottom = viewport.cy - hsize;
            camera.updateProjectionMatrix();
            this.grid.reset(false);
        }
        return {cx: (camera.left + camera.right) / 2, cy: (camera.bottom + camera.top) / 2, size: camera.right - camera.left};
    }

    public viewport_rotate(angle :number) :void {
        var quaternion = new THREE.Quaternion();
        quaternion.setFromAxisAngle(new THREE.Vector3(0, 0, 1), angle);
        this.camera.up.applyQuaternion(quaternion);
        this.camera_update();
    }

    public viewport_zoom(factor :number) :void {
        var viewport = this.viewport();
        if ((factor < 1 && viewport.size > 1) || (factor > 1 && viewport.size < 100)) {
            viewport.size *= factor;
            this.viewport(viewport);
            this.widget.objects.scale(factor);
        }
    }

    public viewport_move(offset :AmvManipulator.MouseMovement) :void {
        var camera = <THREE.OrthographicCamera>this.camera;
        camera.left += offset.deltaX;
        camera.right += offset.deltaX;
        camera.bottom += offset.deltaY;
        camera.top += offset.deltaY;
        camera.updateProjectionMatrix();
        this.grid.reset(false);
    }

    public transform(transformation :AcmacsPlotData.Transformation) :void {
        var m = new THREE.Matrix4();
        m.elements[0] = transformation[0][0];
        m.elements[1] = transformation[0][1];
        m.elements[4] = transformation[1][0];
        m.elements[5] = transformation[1][1];
        var tr = new THREE.Vector3(), qua = new THREE.Quaternion(), scale = new THREE.Vector3();
        m.decompose(tr, qua, scale);
        this.camera.up.applyQuaternion(qua);
        if (scale.x < 0) {
            // flip objects
            (<Objects>this.widget.objects).flip();
        }
        this.camera_update();
    }

    public transformation() :AcmacsPlotData.Transformation {
        var rotation_matrix = new THREE.Matrix4().compose(new THREE.Vector3(),
                                                          new THREE.Quaternion().setFromUnitVectors(this.camera.up, Viewer.camera_up),
                                                          new THREE.Vector3((<Objects>this.widget.objects).flip_state() ? -1 : 1, 1, 1));
        var transformation :AcmacsPlotData.Transformation = [[rotation_matrix.elements[0], rotation_matrix.elements[1]], [rotation_matrix.elements[4], rotation_matrix.elements[5]]];
        return transformation;
    }

    public camera_update() :void {
        super.camera_update();
        this.grid.update();
    }

    public objects_updated() :void {
        super.objects_updated();
        if (!this.viewport_initial) {
            var objects_viewport = this.widget.objects.viewport();
            if (!objects_viewport) {
                var center = this.widget.objects.center();
                objects_viewport = {cx: center.x, cy: center.y, size: Math.ceil(this.widget.objects.diameter() + 0.5)};
            }
            this.viewport_initial = this.viewport(objects_viewport);
        }
        else {
            this.grid.reset(false);
        }
    }

    // Returns node triggering events
    public bind_manipulators(widget :AmvLevel1.MapWidgetLevel1) :void {
        $.when(AmvUtils.require_deferred(['amv-manipulator', 'amv-manipulator-2d'])).done(() => {
            this.manipulator.make_event_generators(["wheel:ctrl:amv", "left:alt:amv", "left:shift-alt:amv",
                                                    "wheel:alt:amv", "wheel:shift:amv", "drag:shift:amv", "key::amv",
                                                    "move::amv", //"drag::amv", "wheel:shift-alt:amv"<commit_msg>applying transformation, flipping in 2d<commit_after>/// <reference path="build/jquery" />
/// <reference path="build/three" />

/// <reference path="antigenic-map-viewer.d.ts" />

import AmvUtils = require("amv-utils");
import AmvLevel1 = require("amv-level1");
import AcmacsPlotData = require("acmacs-plot-data");
import AmvManipulator = require("amv-manipulator");
import AmvManipulator2d = require("amv-manipulator-2d");

// ----------------------------------------------------------------------

export class Viewer extends AmvLevel1.Viewer
{
    public static camera_up = new THREE.Vector3(0, 1, 0);
    private static s_maximum_drawing_order :number = 1000;

    private grid :Grid;
    private maximum_drawing_order :number;
    private viewport_initial :AcmacsPlotData.Viewport; // for reset

    private rotate_control :AmvManipulator2d.RotateControl;
    private fliph_control :AmvManipulator2d.FlipControl;
    private flipv_control :AmvManipulator2d.FlipControl;
    private zoom_control :AmvManipulator2d.ZoomControl;
    private scale_control :AmvManipulator2d.ScaleControl;
    private pan_control :AmvManipulator2d.PanControl;
    private key_control :AmvManipulator2d.KeyControl;
    private hover_control :AmvManipulator2d.HoverControl;

    constructor(widget :AmvLevel1.MapWidgetLevel1) {
        super(widget);
        this.maximum_drawing_order = Viewer.s_maximum_drawing_order;
        this.viewport_initial = null;
        this.camera = new THREE.OrthographicCamera(0, 1, 1, 0, 0, this.maximum_drawing_order + 2);
        widget.add(this.camera);
        this.grid = new Grid(this, 0);
        this.reset()
    }

    // collects current state of the viewer: transformation matrix and viewport
    public state() :void {
        var transformation = this.transformation();
        console.log('transformation', JSON.stringify(transformation));
        var viewport = this.viewport();
    }

    public reset() :void {
        this.widget.reset_objects();
        this.camera.up.copy(Viewer.camera_up);
        this.camera.position.set(0, 0, this.maximum_drawing_order + 1);
        this.camera_look_at(AmvLevel1.Viewer.const_vector3_zero);
        this.viewport(this.viewport_initial);
        this.camera_update();
    }

    public viewport(viewport? :AcmacsPlotData.Viewport) :AcmacsPlotData.Viewport {
        var camera = <THREE.OrthographicCamera>this.camera;
        if (!!viewport) {
            var hsize = viewport.size / 2;
            camera.left = viewport.cx - hsize;
            camera.right = viewport.cx + hsize;
            camera.top = viewport.cy + hsize;
            camera.bottom = viewport.cy - hsize;
            camera.updateProjectionMatrix();
            this.grid.reset(false);
        }
        return {cx: (camera.left + camera.right) / 2, cy: (camera.bottom + camera.top) / 2, size: camera.right - camera.left};
    }

    public viewport_rotate(angle :number) :void {
        var quaternion = new THREE.Quaternion();
        quaternion.setFromAxisAngle(new THREE.Vector3(0, 0, 1), angle);
        this.camera.up.applyQuaternion(quaternion);
        this.camera_update();
    }

    public viewport_zoom(factor :number) :void {
        var viewport = this.viewport();
        if ((factor < 1 && viewport.size > 1) || (factor > 1 && viewport.size < 100)) {
            viewport.size *= factor;
            this.viewport(viewport);
            this.widget.objects.scale(factor);
        }
    }

    public viewport_move(offset :AmvManipulator.MouseMovement) :void {
        var camera = <THREE.OrthographicCamera>this.camera;
        camera.left += offset.deltaX;
        camera.right += offset.deltaX;
        camera.bottom += offset.deltaY;
        camera.top += offset.deltaY;
        camera.updateProjectionMatrix();
        this.grid.reset(false);
    }

    public transform(transformation :AcmacsPlotData.Transformation) :void {
        var m = new THREE.Matrix4();
        m.elements[0] = transformation[0][0];
        m.elements[1] = transformation[0][1];
        m.elements[4] = transformation[1][0];
        m.elements[5] = transformation[1][1];
        //this._set_m4(this._get_m4().multiply(m));
        this._set_m4(m);
    }

    public transformation() :AcmacsPlotData.Transformation {
        var m4 = new THREE.Matrix4().compose(new THREE.Vector3(),
                                             new THREE.Quaternion().setFromUnitVectors(this.camera.up, Viewer.camera_up),
                                             new THREE.Vector3((<Objects>this.widget.objects).flip_state() ? -1 : 1, 1, 1));
        var transformation :AcmacsPlotData.Transformation = [[m4.elements[0], m4.elements[1]], [m4.elements[4], m4.elements[5]]];
        return transformation;
    }

    private _get_m4() :THREE.Matrix4 {
        return new THREE.Matrix4().compose(new THREE.Vector3(),
                                           new THREE.Quaternion().setFromUnitVectors(this.camera.up, Viewer.camera_up),
                                           new THREE.Vector3((<Objects>this.widget.objects).flip_state() ? -1 : 1, 1, 1));
    }

    private _set_m4(m4 :THREE.Matrix4) {
        var t = new THREE.Vector3(), q = new THREE.Quaternion(), s = new THREE.Vector3();
        m4.decompose(t, q, s);
        this.camera.up.applyQuaternion(q);
        if (s.x < 0) {
            (<Objects>this.widget.objects).flip(); // flip objects
        }
        this.camera_update();
    }

    private _reset_m4() :void {
        this.widget.reset_objects();
        this.camera.up.copy(Viewer.camera_up);
    }

    public camera_update() :void {
        super.camera_update();
        this.grid.update();
    }

    public objects_updated() :void {
        super.objects_updated();
        if (!this.viewport_initial) {
            var objects_viewport = this.widget.objects.viewport();
            if (!objects_viewport) {
                var center = this.widget.objects.center();
                objects_viewport = {cx: center.x, cy: center.y, size: Math.ceil(this.widget.objects.diameter() + 0.5)};
            }
            this.viewport_initial = this.viewport(objects_viewport);
        }
        else {
            this.grid.reset(false);
        }
    }

    // Returns node triggering events
    public bind_manipulators(widget :AmvLevel1.MapWidgetLevel1) :void {
        $.when(AmvUtils.require_deferred(['amv-manipulator', 'amv-manipulator-2d'])).done(() => {
            this.manipulator.make_event_generators(["wheel:ctrl:amv", "left:alt:amv", "left:shift-alt:amv",
                                                    "wheel:alt:amv", "wheel:shift:amv", "drag:shift:amv", "key::amv",
                                                    "move::amv", //"drag::amv", "wheel:shift-alt:amv"
{'fraction_non_alphanumeric': 0.135638912423939, 'fraction_numerical': 0.014095355464838635, 'mean_word_length': 2.419541743481696, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1809110', 'n_tokens_mistral': 4056, 'n_tokens_neox': 3881, 'n_words': 697}