Permalink
Browse files

Merge branch 'master' of github.com:ZeusWPI/12Urenloop

Conflicts:
	count-von-count/src/CountVonCount/Web.hs
  • Loading branch information...
2 parents 80f11ad + 7928850 commit 59a16eb99d48dffea8257067bb4d1c91bc42e46c @jaspervdj jaspervdj committed Mar 29, 2012
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Boxxy interpolation demo</title>
+ <!-- Copy the following lines into your visualisation to use the Boxxy API -->
+ <script type="text/javascript">
+ var g = document.createElement('script'),
+ s = document.getElementsByTagName('script')[0];
+ g.src = 'http://' + window.location.hostname + ':8080/boxxy.js';
+ s.parentNode.insertBefore(g, s);
+ </script>
+ <script type="text/javascript" src="/lib/jquery-1.7.1.min.js"></script>
+ <script type="text/javascript" src="/lib/boxxy-interface.js"></script>
+ <script type="text/javascript" src="/lib/interpolation.js"></script>
+
+ <!--
+ To test without a local boxxy server, use the following script tags
+
+ <script type="text/javascript" src="http://live.12urenloop.be:8080/boxxy.js"></script>
+ <script type="text/javascript" src="http://live.12urenloop.be/lib/boxxy-interface.js"></script>
+ -->
+
+ <!-- Use the boxxy information as follows -->
+ <script type="text/javascript">
+ window.onload = function() {
+ var client = new Boxxy(),
+ log = document.getElementById('boxxy-log'),
+ interpolation = new Interpolation();
+
+ client.receivedConfig = function(config) {
+ interpolation.init(config);
+ initCanvas(client, interpolation);
+ for(var id in config.teams) {
+ var team = config.teams[id];
+ var row = $('<tr></tr>').attr('id', team.id)
+ .append($('<td></td>').html(team.name))
+ .append($('<td></td>').html(team.station.position))
+ .append($('<td></td>').html(interpolation.getPosition(team.id)))
+ .append($('<td></td>').html(team.speed))
+ .append($('<td></td>').html(team.speed))
+ .append($('<td></td>').html('---'));
+ $('#teams').append(row);
+ }
+ setInterval(function() {
+ var teams = client.getTeams();
+ for(var teamIdx in teams) {
+ var team = teams[teamIdx];
+ $('#' + team.id).children().eq(2).html(interpolation.getPosition(team.id))
+ }
+ }, 500)
+ }
+ client.updatedPosition = function(message) {
+ var predictedPosition = interpolation.getPosition(message.team.id),
+ error = predictedPosition - message.station.position;
+ error = Math.min(error, 400 - error);
+ interpolation.update(message);
+ $('#' + message.team.id).children().eq(1).html(message.station.position);
+ $('#' + message.team.id).children().eq(3).html(message.speed);
+ $('#' + message.team.id).children().eq(4).html(interpolation.getSpeed(message.team.id));
+ $('#' + message.team.id).children().eq(5).html(error);
+ log.innerHTML = "[POSITION] " + JSON.stringify(message) + "\n" + log.innerHTML;
+
+ }
+ client.connect();
+ }
+ </script>
+ <script type="text/javascript" src="drawing.js"></script>
+</head>
+<body>
+ <h1>Boxxy interpolation demo</h1>
+ <table id="teams">
+ <tr>
+ <th>Team</th>
+ <th>Last position</th>
+ <th>Predicted position</th>
+ <th>Measured speed</th>
+ <th>Interpolation speed</th>
+ <th>Last error</th>
+ </tr>
+ </table>
+ <canvas id="boxxy-interpolation" width="400" height="300"></canvas>
+ <pre id="boxxy-log">
+
+ </pre>
+</body>
+</html>
@@ -0,0 +1,72 @@
+function clearCanvas(){
+ var canvas = document.getElementById("boxxy-interpolation");
+ var context = canvas.getContext("2d");
+ context.clearRect(0, 0, canvas.width, canvas.height);
+}
+
+function drawTeam(name, position) {
+ var canvas = document.getElementById("boxxy-interpolation");
+ var context = canvas.getContext("2d");
+ context.font = "18pt Verdana";
+ context.textAlign = "center";
+ context.fillStyle = "black";
+ context.fillText(name[0], 50 + position.x * 300, 50 + position.y * 300);
+}
+
+function drawStation(id, position) {
+ var canvas = document.getElementById("boxxy-interpolation");
+ var context = canvas.getContext("2d");
+ context.font = "14pt Verdana";
+ context.textAlign = "center";
+ context.fillStyle = "red";
+ context.fillText("" + id, 50 + position.x * 300, 50 + position.y * 300);
+}
+
+function drawCircuit() {
+ var canvas = document.getElementById("boxxy-interpolation");
+ var context = canvas.getContext("2d");
+ context.beginPath();
+ context.rect(50, 50, 300, 300 / 1.62803);
+ context.lineWidth = 10;
+ context.strokeStyle = "#8ED6FF";
+ context.stroke();
+}
+
+function initCanvas(boxxy, interpolation) {
+ var fps = 30;
+
+ window.requestAnimFrame = (function(callback){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback){
+ window.setTimeout(callback, 1000 / fps);
+ };
+ })();
+
+ function frame() {
+ clearCanvas()
+
+ // draw everything!
+ drawCircuit();
+
+ var stations = boxxy.getStations();
+ for(var name in stations) {
+ var station = stations[name];
+ var pos = shapes.rect(station.position / boxxy.circuitLength);
+ drawStation(station.name[station.name.length - 1], pos);
+ }
+ var teams = boxxy.getTeams();
+ for(var idx in teams) {
+ var coords = interpolation.getCoords(teams[idx].id, shapes.rect);
+ drawTeam(teams[idx].name, coords);
+ }
+
+ requestAnimFrame(function(){
+ frame();
+ });
+ }
+ frame();
+}
@@ -41,6 +41,8 @@ function Boxxy() {
for(var idx in self.teams) {
self.ranking.push(self.teams[idx]);
}
+
+ self.circuitLength = config.circuitLength;
updateRanking();
self.receivedConfig(config);
@@ -36,7 +36,11 @@ function Interpolation() {
team.time = new Date(message.time);
team.speed = targetSpeed;
team.station = message.station;
- self.timeOffset = (new Date()) - team.time;
+ // Only correct time once. Can cause jumps otherwise.
+ // TODO: use timestamp from config message
+ if(self.timeOffset == 0) {
+ self.timeOffset = (new Date()) - team.time;
+ }
}
this.getPosition = function(teamid, time) {
@@ -48,6 +52,14 @@ function Interpolation() {
return self.mod(team.lastPosition + distanceTravelled);
}
+ this.getCoords = function(teamid, shape, time) {
+ if(shape == undefined) {
+ shape = shapes.line;
+ }
+ var pos = self.getPosition(teamid, time);
+ return shape(pos / self.circuitLength);
+ }
+
this.getSpeed = function(teamid) {
return self.teams[teamid].speed;
}
@@ -60,3 +72,46 @@ function Interpolation() {
return position;
}
}
+
+var shapes = {
+ // returns a simple line normalized to [0, 1]
+ line: function(pos) {
+ return {
+ x: pos,
+ y: 0
+ };
+ },
+ // Example of a slightly more complex circuit: a rectangle with width 1
+ rect: function(pos) {
+ var ratio = 1.61803, // It's art!
+ width = 1.0,
+ height = 1.0 / ratio,
+ total = 2 * (width + height),
+ progress = pos * total;
+ // Bottom
+ if(progress < width) {
+ return {
+ x: progress,
+ y: 0
+ };
+ // Right
+ } else if(progress < width + height) {
+ return {
+ x: width,
+ y: progress - width
+ };
+ // Top
+ } else if(progress < 2 * width + height) {
+ return {
+ x: width - (progress - width - height),
+ y: height
+ }
+ // Left
+ } else {
+ return {
+ x: 0,
+ y: total - progress
+ }
+ }
+ }
+}
@@ -4,7 +4,7 @@ module CountVonCount.Web
) where
import Control.Applicative (pure, (<$>), (<*>), (<|>))
-import Control.Monad (forM, unless)
+import Control.Monad (forM, unless, forM_)
import Control.Monad.Reader (ReaderT, ask, runReaderT)
import Control.Monad.Trans (liftIO)
import Data.Char (isAlphaNum, isLower)
@@ -31,6 +31,8 @@ import CountVonCount.Log (Log)
import CountVonCount.Management
import CountVonCount.Persistence
import CountVonCount.Web.Util
+import CountVonCount.Boxxy
+import CountVonCount.Types
import qualified CountVonCount.Log as Log
import qualified CountVonCount.Web.Views as Views
@@ -138,13 +140,21 @@ teamBonus :: Web ()
teamBonus = do
Just teamRef <- refFromParam "id"
(view, result) <- runForm "bonus" bonusForm
+ team <- runPersistence $ get teamRef
case result of
Just (BonusForm laps' reason) -> do
timestamp <- liftIO getCurrentTime
+
runPersistence $ addLaps teamRef timestamp reason laps'
+ boxxies <- configBoxxies . webConfig <$> ask
+ logger <- webLog <$> ask
+ liftIO $ forM_ boxxies $ \boxxy -> do
+ let h = handler "Boxxy Bonus" $ \c -> putLaps c team
+ timestamp laps' Nothing (Just reason)
+ callHandler logger h boxxy
+
Snap.redirect "/management"
_ -> do
- team <- runPersistence $ get teamRef
Snap.blaze $ Views.teamBonus teamRef team view
teamReset :: Web ()

0 comments on commit 59a16eb

Please sign in to comment.