Merge "switch image_writer to glog"
diff --git a/y2019/actors/auto_splines.cc b/y2019/actors/auto_splines.cc
index f316037..57aba4e 100644
--- a/y2019/actors/auto_splines.cc
+++ b/y2019/actors/auto_splines.cc
@@ -5,11 +5,72 @@
 namespace y2019 {
 namespace actors {
 
+::frc971::MultiSpline AutonomousSplines::HabToFarRocket() {
+  ::frc971::MultiSpline spline;
+  ::frc971::Constraint longitudinal_constraint;
+  ::frc971::Constraint lateral_constraint;
+  ::frc971::Constraint voltage_constraint;
+  ::frc971::Constraint velocity_constraint;
+
+  longitudinal_constraint.constraint_type = 1;
+  longitudinal_constraint.value = 1.5;
+
+  lateral_constraint.constraint_type = 2;
+  lateral_constraint.value = 1.0;
+
+  voltage_constraint.constraint_type = 3;
+  voltage_constraint.value = 11.0;
+
+  // Note: This velocity constraint is currently too late in the spline to
+  // actually do anything.
+  velocity_constraint.constraint_type = 4;
+  velocity_constraint.value = 0.5;
+  velocity_constraint.start_distance = 7.5;
+  velocity_constraint.end_distance = 10.0;
+
+  spline.spline_count = 1;
+  spline.spline_x = {{1.0, 2.0, 4.0, 7.8, 7.8, 6.53}};
+  spline.spline_y = {{1.5, 1.5, 1.5, 1.5, 3.0, 3.47}};
+  spline.constraints = {{longitudinal_constraint, lateral_constraint,
+                         voltage_constraint, velocity_constraint}};
+  return spline;
+}
+
+::frc971::MultiSpline AutonomousSplines::FarRockettoHP() {
+  ::frc971::MultiSpline spline;
+  ::frc971::Constraint longitudinal_constraint;
+  ::frc971::Constraint lateral_constraint;
+  ::frc971::Constraint voltage_constraint;
+  ::frc971::Constraint velocity_constraint;
+
+  longitudinal_constraint.constraint_type = 1;
+  longitudinal_constraint.value = 1.5;
+
+  lateral_constraint.constraint_type = 2;
+  lateral_constraint.value = 1.0;
+
+  voltage_constraint.constraint_type = 3;
+  voltage_constraint.value = 11.0;
+
+  velocity_constraint.constraint_type = 4;
+  velocity_constraint.value = 0.5;
+  velocity_constraint.start_distance = 7.5;
+  velocity_constraint.end_distance = 10.0;
+
+  spline.spline_count = 1;
+  spline.spline_x = {{6.53, 7.8, 7.8, 4.0, 2.0, 0.4}};
+  spline.spline_y = {{3.47, 3.0, 1.5, 3.0, 3.4, 3.4}};
+  spline.constraints = {{longitudinal_constraint, lateral_constraint,
+                         voltage_constraint, velocity_constraint}};
+  return spline;
+}
+
 ::frc971::MultiSpline AutonomousSplines::HPToNearRocket() {
   ::frc971::MultiSpline spline;
   ::frc971::Constraint longitudinal_constraint;
   ::frc971::Constraint lateral_constraint;
   ::frc971::Constraint voltage_constraint;
+  ::frc971::Constraint velocity_constraint;
 
   longitudinal_constraint.constraint_type = 1;
   longitudinal_constraint.value = 1.0;
@@ -18,13 +79,18 @@
   lateral_constraint.value = 1.0;
 
   voltage_constraint.constraint_type = 3;
-  voltage_constraint.value = 12.0;
+  voltage_constraint.value = 11.0;
+
+  velocity_constraint.constraint_type = 4;
+  velocity_constraint.value = 0.5;
+  velocity_constraint.start_distance = 2.7;
+  velocity_constraint.end_distance = 10.0;
 
   spline.spline_count = 1;
-  spline.spline_x = {{0.4, 1.0, 3.0, 4.0, 4.5, 5.05}};
-  spline.spline_y = {{3.4, 3.4, 3.4, 3.0, 3.0, 3.5}};
-  spline.constraints = {
-      {longitudinal_constraint, lateral_constraint, voltage_constraint}};
+  spline.spline_x = {{1.5, 2.0, 3.0, 4.0, 4.5, 5.12}};
+  spline.spline_y = {{3.4, 3.4, 3.4, 3.0, 3.0, 3.43}};
+  spline.constraints = {{longitudinal_constraint, lateral_constraint,
+                         voltage_constraint, velocity_constraint}};
   return spline;
 }
 
diff --git a/y2019/actors/auto_splines.h b/y2019/actors/auto_splines.h
index 7e79d1f..d093b99 100644
--- a/y2019/actors/auto_splines.h
+++ b/y2019/actors/auto_splines.h
@@ -22,6 +22,9 @@
 
   // HP to near side rocket
   static ::frc971::MultiSpline HPToNearRocket();
+
+  static ::frc971::MultiSpline HabToFarRocket();
+  static ::frc971::MultiSpline FarRockettoHP();
 };
 
 }  // namespace actors
diff --git a/y2019/vision/server/www/field.ts b/y2019/vision/server/www/field.ts
index b52eee8..591b291 100644
--- a/y2019/vision/server/www/field.ts
+++ b/y2019/vision/server/www/field.ts
@@ -1,4 +1,4 @@
-import {IN_TO_M, FT_TO_M} from './constants';
+import {FT_TO_M, IN_TO_M} from './constants';
 
 const CENTER_FIELD_X = 27 * FT_TO_M + 1.125 * IN_TO_M;
 
@@ -37,12 +37,12 @@
 
 const DEPOT_WIDTH = (12 + 10.625) * IN_TO_M;
 
-export function drawField(ctx : CanvasRenderingContext2D) : void {
+export function drawField(ctx: CanvasRenderingContext2D): void {
   drawTargets(ctx);
   drawHab(ctx);
 }
 
-function drawHab(ctx : CanvasRenderingContext2D) : void {
+function drawHab(ctx: CanvasRenderingContext2D): void {
   drawHalfHab(ctx);
   ctx.save();
 
@@ -52,7 +52,7 @@
   ctx.restore();
 }
 
-function drawHalfHab(ctx : CanvasRenderingContext2D) : void {
+function drawHalfHab(ctx: CanvasRenderingContext2D): void {
   ctx.fillStyle = 'rgb(50, 50, 50)';
   ctx.fillRect(0, 0, HAB_LENGTH, HALF_HAB_3_WIDTH);
   ctx.fillStyle = 'rgb(100, 100, 100)';
@@ -62,7 +62,7 @@
   ctx.strokeRect(0, HALF_HAB_3_WIDTH + HAB_2_WIDTH, HAB_LENGTH, DEPOT_WIDTH);
 }
 
-function drawTargets(ctx : CanvasRenderingContext2D) : void {
+function drawTargets(ctx: CanvasRenderingContext2D): void {
   drawHalfCargo(ctx);
   drawRocket(ctx);
   drawHP(ctx);
@@ -76,11 +76,11 @@
   ctx.restore();
 }
 
-function drawHP(ctx : CanvasRenderingContext2D) : void {
+function drawHP(ctx: CanvasRenderingContext2D): void {
   drawTarget(ctx, 0, HP_Y, HP_THETA);
 }
 
-function drawRocket(ctx : CanvasRenderingContext2D) : void {
+function drawRocket(ctx: CanvasRenderingContext2D): void {
   drawTarget(ctx, ROCKET_PORT_X, ROCKET_PORT_Y, ROCKET_PORT_THETA);
 
   drawTarget(ctx, ROCKET_NEAR_X, ROCKET_HATCH_Y, ROCKET_NEAR_THETA);
@@ -88,7 +88,7 @@
   drawTarget(ctx, ROCKET_FAR_X, ROCKET_HATCH_Y, ROCKET_FAR_THETA);
 }
 
-function drawHalfCargo(ctx : CanvasRenderingContext2D) : void {
+function drawHalfCargo(ctx: CanvasRenderingContext2D): void {
   drawTarget(ctx, FAR_CARGO_X, SIDE_CARGO_Y, SIDE_CARGO_THETA);
 
   drawTarget(ctx, MID_CARGO_X, SIDE_CARGO_Y, SIDE_CARGO_THETA);
@@ -98,7 +98,8 @@
   drawTarget(ctx, FACE_CARGO_X, FACE_CARGO_Y, FACE_CARGO_THETA);
 }
 
-export function drawTarget(ctx : CanvasRenderingContext2D, x: number, y: number, theta: number) : void {
+export function drawTarget(
+    ctx: CanvasRenderingContext2D, x: number, y: number, theta: number): void {
   ctx.save();
   ctx.translate(x, y);
   ctx.rotate(theta);
diff --git a/y2019/vision/server/www/main.ts b/y2019/vision/server/www/main.ts
index beb2734..a260787 100644
--- a/y2019/vision/server/www/main.ts
+++ b/y2019/vision/server/www/main.ts
@@ -1,4 +1,4 @@
-import {FT_TO_M, FIELD_WIDTH} from './constants';
+import {FIELD_WIDTH, FT_TO_M} from './constants';
 import {drawField, drawTarget} from './field';
 import {drawRobot} from './robot';
 
@@ -23,6 +23,11 @@
     const ctx = canvas.getContext('2d');
 
     const server = location.host;
+    this.initWebSocket(server);
+    window.requestAnimationFrame(() => this.draw(ctx));
+  }
+
+  initWebSocket(server: string): void {
     const socket = new WebSocket(`ws://${server}/ws`);
     const reader = new FileReader();
     reader.addEventListener('loadend', (e) => {
@@ -32,8 +37,9 @@
       this.y = j.robotPose.y;
       this.theta = j.robotPose.theta;
 
-      if(j.lineFollowDebug) {
-        this.targetLocked = j.lineFollowDebug.frozen && j.lineFollowDebug.haveTarget;
+      if (j.lineFollowDebug) {
+        this.targetLocked =
+            j.lineFollowDebug.frozen && j.lineFollowDebug.haveTarget;
         this.targetX = j.lineFollowDebug.goalTarget.x;
         this.targetY = j.lineFollowDebug.goalTarget.y;
         this.targetTheta = j.lineFollowDebug.goalTarget.theta;
@@ -49,17 +55,21 @@
     socket.addEventListener('message', (event) => {
       reader.readAsText(event.data);
     });
-    window.requestAnimationFrame(() => this.draw(ctx));
+    socket.addEventListener('close', (event) => {
+      setTimeout(() => {
+        this.initWebSocket(server);
+      }, 1000);
+    });
   }
 
-  reset(ctx : CanvasRenderingContext2D) : void {
-    ctx.setTransform(1,0,0,1,0,0);
+  reset(ctx: CanvasRenderingContext2D): void {
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
     const size = Math.min(window.innerHeight, window.innerWidth) * 0.98;
     ctx.canvas.height = size;
     ctx.canvas.width = size;
-    ctx.clearRect(0,0,size,size);
+    ctx.clearRect(0, 0, size, size);
 
-    ctx.translate(size/2, size);
+    ctx.translate(size / 2, size);
     ctx.rotate(-Math.PI / 2);
     ctx.scale(1, -1);
     const M_TO_PX = size / FIELD_WIDTH
@@ -67,7 +77,7 @@
     ctx.lineWidth = 1 / M_TO_PX;
   }
 
-  draw(ctx : CanvasRenderingContext2D) : void {
+  draw(ctx: CanvasRenderingContext2D): void {
     this.reset(ctx);
 
     drawField(ctx);
diff --git a/y2019/vision/server/www/robot.ts b/y2019/vision/server/www/robot.ts
index 489112c..6329fb3 100644
--- a/y2019/vision/server/www/robot.ts
+++ b/y2019/vision/server/www/robot.ts
@@ -1,22 +1,28 @@
-import {IN_TO_M, FT_TO_M} from './constants';
 import {CAMERA_POSES} from './camera_constants';
+import {FT_TO_M, IN_TO_M} from './constants';
 
 const ROBOT_WIDTH = 25 * IN_TO_M;
 const ROBOT_LENGTH = 31 * IN_TO_M;
 const CAMERA_SCALE = 0.3;
 
-function drawCamera(ctx : canvasRenderingContext2d, pose : {x : number, y : number, theta : number}) : void {
+function drawCamera(
+    ctx: CanvasRenderingContext2D,
+    pose: {x: number, y: number, theta: number}): void {
   ctx.beginPath();
   ctx.moveTo(pose.x, pose.y);
-  ctx.lineTo(pose.x + CAMERA_SCALE * Math.cos(pose.theta + Math.PI / 4.0),
-             pose.y + CAMERA_SCALE * Math.sin(pose.theta + Math.PI / 4.0));
-  ctx.lineTo(pose.x + CAMERA_SCALE * Math.cos(pose.theta - Math.PI / 4.0),
-             pose.y + CAMERA_SCALE * Math.sin(pose.theta - Math.PI / 4.0));
+  ctx.lineTo(
+      pose.x + CAMERA_SCALE * Math.cos(pose.theta + Math.PI / 4.0),
+      pose.y + CAMERA_SCALE * Math.sin(pose.theta + Math.PI / 4.0));
+  ctx.lineTo(
+      pose.x + CAMERA_SCALE * Math.cos(pose.theta - Math.PI / 4.0),
+      pose.y + CAMERA_SCALE * Math.sin(pose.theta - Math.PI / 4.0));
   ctx.closePath();
   ctx.stroke();
 }
 
-export function drawRobot(ctx : CanvasRenderingContext2D, x : number, y : number, theta : number, camera_colors : string[]) : void {
+export function drawRobot(
+    ctx: CanvasRenderingContext2D, x: number, y: number, theta: number,
+    camera_colors: string[]): void {
   ctx.save();
   ctx.translate(x, y);
   ctx.rotate(theta);
@@ -26,9 +32,9 @@
 
   ctx.beginPath();
   ctx.strokeStyle = 'black';
-  ctx.moveTo(ROBOT_LENGTH / 2, -ROBOT_WIDTH/2);
+  ctx.moveTo(ROBOT_LENGTH / 2, -ROBOT_WIDTH / 2);
   ctx.lineTo(ROBOT_LENGTH / 2 + 0.1, 0);
-  ctx.lineTo(ROBOT_LENGTH / 2, ROBOT_WIDTH/2);
+  ctx.lineTo(ROBOT_LENGTH / 2, ROBOT_WIDTH / 2);
   ctx.closePath();
   ctx.stroke();
   ctx.lineWidth = 3.0 * ctx.lineWidth;