dasantonym/wdt

View on GitHub
src/js/controllers/space.js

Summary

Maintainability
F
3 days
Test Coverage
/* global console,angular,require */
(function () {
    'use strict';
    angular.module(
        'wdt.controllers.space', [])
        .controller('Space', ['$scope', '$routeParams', function ($scope, $routeParams) {

            switch ($routeParams.spaceModule) {
                case "inertia":
                    $scope.exercises = [
                        { type: "Inertia" }
                    ];
                    break;
                case "cage":
                    $scope.exercises = [
                        { type: "Cage", left: 0.2, top: 0.2, right: 0.8, bottom: 1.1 },
                        { type: "Cage", left: 0.35, top: 0.15, right: 0.6, bottom: 1.1 }
                    ];
                    break;
                default:
                    $scope.exercises = [
                        { type: "StandAtAngle", angle: 45.0 },
                        { type: "StandAtAngle", angle: 0.0 },
                        { type: "StandAtAngle", angle: 180.0 },
                        { type: "StandAtAngle", angle: 316.0 },
                        { type: "MoveTo", x: 0.8, y: 0.7 },
                        { type: "StandAtAngle", angle: 95.0 },
                        { type: "MoveTo", x: 0.1, y: 0.75 },
                        { type: "StandAtAngle", angle: 212.0 },
                        { type: "StandAtAngle", angle: 114.0 },
                        { type: "MoveTo", x: 0.9, y: 0.23 }
                    ];
                    break;
            }

            $scope.exerciseIndex = 0;
            $scope.exercise = $scope.exercises[$scope.exerciseIndex];

            $scope.nextExercise = function () {
                $scope.exerciseIndex = ($scope.exerciseIndex + 1) % $scope.exercises.length;
                $scope.exercise = $scope.exercises[$scope.exerciseIndex];
            };
            $scope.previousExercise = function () {
                $scope.exerciseIndex = ($scope.exerciseIndex - 1) % $scope.exercises.length;
                if ($scope.exerciseIndex < 0) {
                    $scope.exerciseIndex = $scope.exercises.length - 1;
                }
                $scope.exercise = $scope.exercises[$scope.exerciseIndex];
            };

            $scope.exerciseDone = function () {
                snd.play();
                $scope.nextExercise();
            };

            $scope.OSDOpacity = 0;
            var fade;
            $scope.showOSD = function () {
                $scope.OSDOpacity = 1;
                if (!fade) {
                    fade = setInterval(function () {
                        $scope.OSDOpacity *= 0.9;
                        if ($scope.OSDOpacity < 0.01) {
                            $scope.OSDOpacity = 0;
                            clearInterval(fade);
                            fade = undefined;
                        }
                        $scope.$apply();
                    }, 66);
                }
            };

            function deg2rad(v) {
                return ((v / 180) * -Math.PI);
            }

            $scope.threshold = 100;

            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");

            var width = 320;
            var height = 240;

            $scope.inert = { x: width / 2, y: height / 2 };
            $scope.vel = { x: 0.0, y: 0.0 };

            var snd = new Audio("./snd/Robot_blip_2-Marianne_Gagnon-299056732.wav");

            var cv = require('wdt-native');

            var camDevice = 0;

            var cam = new cv.VideoCapture(camDevice);
            var extremes = new cv.wExtremes();
            var motion = new cv.cvMotion();
            var accumulate = new cv.wAccumulate();
            var multiplys = new cv.cvMultiplyS();
            var camshift = new cv.cvCamShift();
            //var displayFormat = new cv.cvDisplayFormat();

            cam.setWidth(width);
            cam.setHeight(height);

            /*
            var pipeline = new gstreamer.Pipeline(
                //"videotestsrc pattern=snow"
                    "v4l2src"
                    + " ! videoconvert ! video/x-raw, format=GRAY8, width=320, height=240"
                    + " ! motion name=motion weight=0.000001 scale=2 shift=-10 ! videoconvert "
                    + " ! flip h=true ! blur ! threshold name=threshold threshold=" + $scope.threshold
                    + " ! extremes name=extremes ! camshift name=camshift ! acc "
                    + " ! multiplys scale=.6 "
                    + " ! videoconvert ! video/x-raw, format=RGBA ! appsink name=sink");

            var appsink = pipeline.findChild("sink");
            var motion = pipeline.findChild("motion");
            var extremes = pipeline.findChild("extremes");
            var camshift = pipeline.findChild("camshift");
            var threshold = pipeline.findChild("threshold");
            */

            var videoContainer = document.getElementById("video-container");
            var canvasContainer = document.getElementById("canvas-container");
            window.onresize = function (e) {
                var ww = window.innerWidth;
                var wh = window.innerHeight;

                var scale = Math.min(ww / width, wh / height);
                canvasContainer.style.webkitTransform = "scale(" + scale + "," + scale + ")";

                var ofsx = (ww - width) / 2;
                var ofsy = (wh - height) / 2;
                videoContainer.style.left = "" + (ofsx) + "px";
                videoContainer.style.top = "" + (ofsy) + "px";
            };

            document.onkeydown = function (e) {
                switch (e.keyCode) {
                    case 38: // up
                        $scope.threshold = Math.min(255, $scope.threshold + 3);
                        $scope.showOSD();
                        //threshold.set("threshold", $scope.threshold);
                        break;
                    case 40: // down
                        $scope.threshold = Math.max(0, $scope.threshold - 3);
                        $scope.showOSD();
                        //threshold.set("threshold", $scope.threshold);
                        break;
                    case 39: // right
                        $scope.nextExercise();
                        break;
                    case 37: // left;
                        $scope.previousExercise();
                        break;
                    case 32: // space:
                        motion.reset();
                        break;
                    case 67: // c:
                        try {
                            camDevice += 1;
                            cam.close();
                            cam = new cv.VideoCapture(camDevice);
                        } catch (e) {
                            camDevice = 0;
                            cam = new cv.VideoCapture(camDevice);
                        }
                        cam.setWidth(width);
                        cam.setHeight(height);
                        break;
                    case 81: // Q
                        //pipeline.stop();
                        cam.close();
                        cam = undefined;
                        window.location = "index.html";
                        break;
                    default:
                        console.log("unhandled key code " + e.keyCode);
                }
                $scope.$apply();
            };

            var readFrame = function () {
                cam.read(function(err, mat){
                    mat.convertGrayscale();
                    motion.process(mat, 0.000001, 2.0, -10.0, 0);
                    mat = mat.flip(1);
                    mat.gaussianBlur();
                    mat = mat.threshold($scope.threshold, 255);
                    mat.cvtColor('CV_GRAY2BGR');
                    var extRes = extremes.process(mat);
                    var camshiftRes = camshift.process(mat);
                    accumulate.process(mat, 0.2, 0.8);
                    multiplys.process(mat, 0.6, 0);
                    //displayFormat.process(mat);


                    var image = context.createImageData(mat.width(), mat.height());
                    //image.data.set(mat.toBuffer());

                    var width = mat.width();
                    var height = mat.height();
                    for (var y = 0; y < height; y += 1) {
                        for (var x = 0; x < width; x += 1) {
                            var pixel = mat.pixel(y, x);
                            var pos = (width * y + x) * 4;
                            image.data[pos] = pixel[2];
                            image.data[pos + 1] = pixel[1];
                            image.data[pos + 2] = pixel[0];
                            image.data[pos + 3] = 255;
                        }
                    }
                    context.putImageData(image, 0, 0);

                    var extr = $scope.extremes = {
                        left: extRes[0] * width,
                        top: extRes[2] * height,
                        right: extRes[1] * width,
                        bottom: extRes[3] * height
                    };

                    if (!camshiftRes) {
                        window.setTimeout(readFrame, 10);
                        return;
                    }

                    var c = $scope.centroid = {
                        x: Math.floor(camshiftRes[0] * width),
                        y: Math.floor(camshiftRes[1] * height),
                        width: Math.floor(camshiftRes[2] * width),
                        height: Math.floor(camshiftRes[3] * height),
                        angle: deg2rad(camshiftRes[4])
                    };

                    context.fillStyle = "#0f0";
                    context.save();
                    context.translate(c.x, c.y);
                    context.rotate(c.angle);
                    context.fillRect(-(c.width / 2), -5, c.width, 10);
                    context.fillRect(-5, -(c.height / 2), 10, c.height);
                    context.fillStyle = "#ff0";
                    context.fillRect(-5, c.height / 2 - 10, 10, 10);
                    context.restore();

                    context.strokeStyle = "#f00";
                    context.lineWidth = 2;
                    context.strokeRect(extr.left, extr.top, extr.right - extr.left, extr.bottom - extr.top);

                    // inert centroid
                    var acc = 0.05; // TODO: make configurable
                    var brake = 1.0 - acc;
                    var inert = $scope.inert;
                    var vel = $scope.vel;
                    var d = { x: c.x - inert.x, y: c.y - inert.y };
                    d.x *= acc;
                    d.y *= acc;
                    vel.x *= brake;
                    vel.y *= brake;
                    vel.x += d.x;
                    vel.y += d.y;
                    inert.x += vel.x;
                    inert.y += vel.y;

                    $scope.inert = inert;
                    $scope.vel = vel;

                    var ex = $scope.exercise;
                    context.fillStyle = "#fff";
                    var th = 2;
                    var sz = 30;
                    context.save();
                    switch (ex.type) {
                        case "StandAtAngle":
                            var angle = deg2rad(ex.angle);
                            context.translate(width / 2, height / 2);
                            context.rotate(angle);
                            context.fillRect(-width / 2, -2, width, 4);
                            var delta = Math.abs(angle - c.angle);
                            $scope.delta = delta;
                            if (delta < Math.abs(deg2rad(3))) {
                                $scope.exerciseDone();
                            }
                            break;

                        case "MoveTo":
                            var x = ex.x * width;
                            var y = ex.y * height;
                            context.fillRect(x - th, y - sz, th * 2, sz * 2);
                            context.fillRect(x - sz, y - th, sz * 2, th * 2);

                            var d = { x: x - c.x, y: y - c.y };
                            var delta = Math.sqrt((d.x * d.x) + (d.y * d.y));
                            $scope.delta = delta;
                            if (delta < 10) {
                                $scope.exerciseDone();
                            }
                            break;

                        case "Cage":
                            var cg = {
                                l: ex.left * width,
                                t: ex.top * height,
                                r: ex.right * width,
                                b: ex.bottom * height
                            };
                            var inside = cg.l < extr.left && cg.t < extr.top && cg.r > extr.right && cg.b >= extr.bottom;
                            $scope.insideCage = inside;
                            context.strokeStyle = inside ? "#0f0" : "#f00";
                            context.lineWidth = 2;
                            context.strokeRect(cg.l, cg.t, cg.r - cg.l, cg.b - cg.t);
                            break;

                        case "Inertia":
                            var x = $scope.inert.x;
                            var y = $scope.inert.y;
                            context.fillRect(x - th, y - sz, th * 2, sz * 2);
                            context.fillRect(x - sz, y - th, sz * 2, th * 2);
                            break;

                    }
                    context.restore();

                    $scope.$apply();

                    window.setTimeout(readFrame, 10);
                });
            };

            $scope.$on('$routeChangeStart', function(next, current) {
                if (next !== current) {
                    cam.close();
                    cam = undefined;
                }
            });

            window.onresize();
            readFrame();

        }]);
})();