ensilico
Version:
Synthetic data generation, simulated vehicles
153 lines (129 loc) • 5.8 kB
HTML
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no">
<style>
.unselectable {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>
<script src="ensilico.js"></script>
<script>
function Cast() {
this.bot = new Bot();
this.rod = new Flexor();
this.rod.alignTo(this.bot.angle);
this.lure = new Particle();
this.lure.position
.load(this.rod.tipPosition)
.add({x: 4, y: 0});
this.line = new Filament(this.rod.tipPosition, this.lure.position);
// A value of 0 will "pin" the lure in place
this.lureWarp = 1;
// A value of 0 will detach and freeze the line
this.lineCoupler = 1;
// Use closure to avoid object allocation in inner loop
var reusage = {
headForce: new Pair(),
tailForce: new Pair(),
targetPosition: new Pair(),
targetVelocity: new Pair()
};
this.reusage = function() {
return reusage;
};
}
Cast.geosphere = (function() {
var waterlineY = -2;
var densityWaterToAir = 784;
return {
gravity: new Pair().load({
x: 0,
y: -9.81
}),
surfaceHeight: function() {
return waterlineY;
},
density: function(position) {
return position.y > waterlineY ? 1 : densityWaterToAir;
}
};
})();
Cast.prototype.preferences = {
visualScale: 32,
stepsize: 0.00025
};
Cast.prototype.update = function(controls) {
var stepsize = controls.stepsize;
var reusage = this.reusage();
var headForce = reusage.headForce;
var tailForce = reusage.tailForce;
var targetPosition = reusage.targetPosition;
var targetVelocity = reusage.targetVelocity;
this.line.update(
stepsize * this.lineCoupler,
Cast.geosphere,
this.rod.tipPosition,
this.rod.tipVelocity,
this.lure.position,
this.lure.velocity);
this.line.storeTailForce(Cast.geosphere, tailForce);
this.lure.update(
stepsize * this.lineCoupler * this.lureWarp,
Cast.geosphere,
tailForce);
this.bot.update(stepsize, controls.pointer.velocity.y);
this.line.storeHeadForce(Cast.geosphere, headForce);
headForce.multiplyBy(this.lineCoupler);
targetPosition.loadPolar(this.rod.radius(), this.bot.angle);
targetVelocity.loadCrossProduct(this.bot.rate, targetPosition);
this.rod.update(stepsize, Cast.geosphere, headForce, targetPosition, targetVelocity);
};
Cast.prototype.visualize = function(context, elapsedTime) {
context.save();
context.translate(3, -3);
var waterlineY = Cast.geosphere.surfaceHeight();
context.moveTo(-12, waterlineY);
context.lineTo(6, waterlineY);
// Rod flex curve
var r = -this.rod.pivotOffset;
var x = Math.cos(this.bot.angle);
var y = Math.sin(this.bot.angle);
context.moveTo(r * x, r * y);
r = 0.75 * this.rod.radius();
context.quadraticCurveTo(r * x, r * y, this.rod.tipPosition.x, this.rod.tipPosition.y);
if (this.lineCoupler) {
this.line.visualize(context, elapsedTime);
}
context.restore();
};
function Bot() {
// Default values
this.minAngle = 0;
this.maxAngle = Scalar.toRadians(90);
this.gain = 0.01;
this.responsiveness = 5;
this.angle = this.minAngle;
this.rate = 0;
}
Bot.prototype.update = function(stepsize, pointerVelocity) {
var target = this.gain * pointerVelocity;
this.rate = Scalar.lag(this.rate, target, this.responsiveness, stepsize);
this.angle = Math.min(
Math.max(this.minAngle, Scalar.integrate(this.angle, this.rate, stepsize)),
this.maxAngle);
};
var theSim; // for debug
var tmpDst; // for debug
</script>
</head>
<body onload="Executive.start('cast', new Cast(), 'cast.json')" class="unselectable">
<canvas id="cast" width="800" height="600">
Opps.
</canvas>
<button onclick="Executive.breakFrame('cast', function(sim){theSim=sim;})">Break</button>
<button onclick="Platform.load(new Cast(), 'cast.json', function(msg){console.log(msg);}, function(dst){tmpDst=dst;debugger;})">Check</button>
</body>
</html>