Last active
August 29, 2015 14:06
-
-
Save dannyko/c31420dfd63a7c2304bf to your computer and use it in GitHub Desktop.
Revisions
-
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,4 @@ ### Rainflow Gradient flow example using bilinear interpolation of matrix map of Earth altitudes. -
dannyko revised this gist
Sep 14, 2014 . No changes.There are no files selected for viewing
-
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 5 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,10 +3,12 @@ Rainflow Gradient flow example using bilinear interpolation of matrix map of Earth altitudes. For this example, I computed the gravitational force field from a gradient of a 2-D potential energy function, in this case a bilinearly interpolated matrix map of average altitudes of the Earth at every degree (a 180-by-360 dataset). This global elevation dataset is included with Matlab and is available by running "Load topo". Their doc page references National Geophysical Data Center, NOAA US Department of Commerce under data announcement 88-MGG-02: [http://www.ngdc.noaa.gov/mgg/global/etopo5.HTML](http://www.ngdc.noaa.gov/mgg/global/etopo5.HTML) I used the physics engine from the open-source HTML5 game dev kit (built using d3) that I've been working on, available on Github at: [http://github.com/gameprez/gpdk](http://github.com/gameprez/gpdk) -
dannyko revised this gist
Sep 14, 2014 . No changes.There are no files selected for viewing
-
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,5 @@ Rainflow ======== Gradient flow example using bilinear interpolation of matrix map of Earth altitudes. -
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 10 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,11 @@ =Rainflow= Gradient flow example using bilinear interpolation of matrix map of Earth altitudes. For this example, I computed a Newtonian force field from a 2-D potential energy function, in this case coming from the matrix map of average altitudes of the Earth at every degree (a 180-by-360 dataset). This global elevation dataset is included with Matlab and is available by running "Load topo" i think. Their doc page references National Geophysical Data Center, NOAA US Department of Commerce under data announcement 88-MGG-02. I used the physics engine from the open-source HTML5 game dev kit (built using d3) that I've been working on, available on Github at: http://github.com/gameprez/gpdk -
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 1 addition and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1351,18 +1351,11 @@ }; Physics.integrate = function(t) { var fps; if (Physics.off) { return true; } Physics.elapsedTime = t - Physics.timestamp; if (Physics.debug) { fps = 1000 / elapsedTime; console.log('Physics.integrate:', 'dt: ', elapsedTime, 't: ', t, 'timestamp: ', Physics.timestamp, 'dt_chk: ', t - Physics.timestamp, 'fps: ' + fps); -
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 53 additions and 49 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -550,13 +550,6 @@ return this; }; Element.prototype.scale = function(scalingFactor, dur, callback) { if (scalingFactor == null) { scalingFactor = 10; @@ -1322,6 +1315,10 @@ Physics.tick = 1000 / Physics.fps; Physics.maxElapsedTime = 100 * Physics.tick; Physics.Nstep = 2; Physics.off = true; Physics.game = null; @@ -1354,63 +1351,59 @@ }; Physics.integrate = function(t) { var dur, fps; if (Physics.off) { return true; } Physics.elapsedTime = t - Physics.timestamp; if (Physics.elapsedTime > Physics.maxElapsedTime) { dur = 2000; Physics.stop(); $z.Game.instance.message('CPU SPEED ERROR', function() { return $z.Game.instance.stop(); }, dur); } if (Physics.debug) { fps = 1000 / elapsedTime; console.log('Physics.integrate:', 'dt: ', elapsedTime, 't: ', t, 'timestamp: ', Physics.timestamp, 'dt_chk: ', t - Physics.timestamp, 'fps: ' + fps); } Physics.timestamp = t; Physics.update(); return Physics.off; }; Physics.update = function() { Physics.step(); $z.Collision.detect(); Physics.draw_all(); return Physics.run_callbacks(); }; Physics.step = function() { var element, index, stepCount, _results; stepCount = 0; _results = []; while (stepCount < Physics.Nstep) { stepCount++; index = $z.Collision.list.length; _results.push((function() { var _results1; _results1 = []; while (index--) { if ($z.Collision.list[index].is_removed) { _results1.push($z.Utils.index_pop($z.Collision.list, index).sleep()); } else { element = $z.Collision.list[index]; element.tick(element, Physics.elapsedTime / Physics.Nstep); if (Physics.debug) { _results1.push(console.log('Physics.update', 'index:', index, 'fps:', fps, 'r.x:', $z.Collision.list[index].r.x, 'r.y:', $z.Collision.list[index].r.y)); } else { _results1.push(void 0); } } } return _results1; })()); } return _results; }; @@ -1433,6 +1426,17 @@ return _results; }; Physics.draw_all = function() { var element, index, _results; index = $z.Collision.list.length; _results = []; while (index--) { element = $z.Collision.list[index]; _results.push(element.draw()); } return _results; }; Physics.start = function() { var blurCallback; if (!Physics.off) { @@ -1796,7 +1800,7 @@ if (y > _this.elevation.length - 1) { y = y % (_this.elevation.length - 1); } scale = 1e-6; return energy = scale * $z.Utils.bilinear_interp(_this.elevation, x, y); }; })(this); -
dannyko revised this gist
Sep 14, 2014 . 1 changed file with 2 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1796,9 +1796,8 @@ if (y > _this.elevation.length - 1) { y = y % (_this.elevation.length - 1); } scale = 4e-6; return energy = scale * $z.Utils.bilinear_interp(_this.elevation, x, y); }; })(this); } @@ -1834,7 +1833,6 @@ new_drop = function() { $z.Factory.spawn($z.Drop, config.pop()).start(); if (config.length === 0) { clear(); return $z.Game.instance.raining = false; } -
dannyko revised this gist
Sep 13, 2014 . 4 changed files with 2132 additions and 0 deletions.There are no files selected for viewing
LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,63 @@ <!DOCTYPE HTML> <html style="height:100%;width:100%;"> <head> <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script><!-- http://d3js.org/--> <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script> </head> <body oncontextmenu="return false;" style="border:0;padding:0;margin:0;overflow:hidden;height:100%;width:100%;"> <div id="game_div" style="margin-left: auto; margin-right: auto; height:100%;width:100%;"> <svg id="game_svg" style="margin-left:auto; margin-right: auto; display:block;"> <g id="game_g"> </g> </svg> </div> <!-- run the game: --> <script type="text/javascript" src="rainflow.js"></script><!-- use a single .js file for deployment, run "cake build" to recompile --> </body> </html> <!-- <!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/> <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script><!-- http://coffeescript.org/extras/--> <!-- <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script><!-- http://d3js.org/--> <!-- <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script> <style type="text/css"> body { width: 100%; margin: 0; padding: 0; padding-left: 10px; overflow: hidden; } svg { display: block; margin:auto; } </style> </head> <body> <div id="map" oncontextmenu="return false"> <svg id="game_svg" width="360px" height="180px"> </svg> </div> <!-- run the game: --> <!--<script type="text/javascript" src="rainflow.js"></script><!-- use a single .js file for deployment, run "cake build" to recompile --> <!--<script type="text/javascript"> $(document).ready( function() { new Rainflow().start() ; // create and start the visualization }) ; </script> </body> </html> --> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,1889 @@ // Generated by CoffeeScript 1.7.1 (function() { var $z, __slice = [].slice, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; $z = {}; $z.Factory = (function() { function Factory() {} Factory.inactive = {}; Factory.spawn = function(klass, config, callback) { var old; if (this.inactive[klass] === void 0) { this.inactive[klass] = []; } if (this.inactive[klass].length === 0) { old = new klass(config); } else { old = this.inactive[klass].pop(); if (old.is_sleeping === false || old.is_removed === false) { console.log('$z.Factory.spawn: not sleeping & unremoved instance found in inactive list!', old); $z.Factory.spawn(klass, config); return; } if (old.wake != null) { old.wake(config); } else { $z.Utils.set(old, config); } } if (typeof callback === "function") { callback(old); } return old; }; Factory.sleep = function(instance) { var _ref; if (instance === void 0) { console.log('$z.Factory.sleep(): undefined input', instance); return; } if (instance.is_sleeping === true) { console.log('$z.Factory.sleep(): sleeping instance', instance, this.inactive[instance.constructor].indexOf(instance)); return; } if ((_ref = this.inactive[instance.constructor]) != null) { _ref.push(instance); } }; return Factory; })(); $z.Gamescore = (function() { function Gamescore() {} Gamescore.value = 0; Gamescore.increment = 100; Gamescore.initialLives = 2; Gamescore.lives = Gamescore.initialLives; Gamescore.increment_value = function() { return this.value += this.increment; }; Gamescore.decrement_value = function() { return this.value -= this.increment; }; return Gamescore; })(); $z.ImageLoader = (function() { function ImageLoader() {} ImageLoader.loading = false; ImageLoader.cache = {}; ImageLoader.loadingStats = { total: null, count: null, finalCallback: null }; ImageLoader.load = function(url) { var img; if (this.cache[url] != null) { this.callbackHandler(); } else { img = new Image(); img.onload = $z.ImageLoader.callbackHandler; img.src = url; this.cache[url] = img; } return img; }; ImageLoader.callbackHandler = function() { $z.ImageLoader.loadingStats.count++; if ($z.ImageLoader.loadingStats.count === $z.ImageLoader.loadingStats.total) { $z.ImageLoader.loadingStats.finalCallback(); $z.ImageLoader.loading = false; } }; ImageLoader.preload = function(imageList, callback) { var url, _i, _len; if (this.loading) { return; } this.loading = true; this.loadingStats.total = imageList.length; this.loadingStats.count = 0; this.loadingStats.finalCallback = callback; for (_i = 0, _len = imageList.length; _i < _len; _i++) { url = imageList[_i]; this.load(url); } }; return ImageLoader; })(); $z.Utils = (function() { function Utils() {} Utils.fullscreen = function() { var elem; elem = document.body.parentNode; if (elem.requestFullscreen) { return elem.requestFullscreen(); } else if (elem.msRequestFullscreen) { return elem.msRequestFullscreen(); } else if (elem.mozRequestFullScreen) { return elem.mozRequestFullScreen(); } else if (elem.webkitRequestFullscreen) { return elem.webkitRequestFullscreen(); } }; Utils.defaultscreen = function() { var elem; elem = document; if (elem.exitFullscreen) { return elem.exitFullscreen(); } else if (elem.msExitFullscreen) { return elem.msExitFullscreen(); } else if (elem.mozExitFullScreen) { return elem.mozExitFullScreen(); } else if (elem.webkitExitFullscreen) { return elem.webkitExitFullscreen(); } }; Utils.index_pop = function(array, index) { var length, swap; length = array.length; if (index < array.length - 1) { swap = array[index]; array[index] = array[length - 1]; array[length - 1] = swap; } return array.pop(); }; Utils.delayedLoop = function(dur, Niter, callback, finalCallback) { var i, runLoop; if (dur == null) { dur = 1000; } if (finalCallback == null) { finalCallback = void 0; } i = 0; runLoop = function() { callback(i); if (++i === Niter) { if (typeof finalCallback === "function") { finalCallback(); } return; } return setTimeout(runLoop, dur); }; return runLoop(); }; Utils.set = function(obj, config) { var x, _results; _results = []; for (x in config) { _results.push(obj[x] = config[x]); } return _results; }; Utils.clone = function(obj) { var key, temp; if (obj === null || typeof obj !== "object") { return obj; } temp = new obj.constructor(); for (key in obj) { temp[key] = $z.Utils.clone(obj[key]); } return temp; }; Utils.addChainedAttributeAccessor = function(obj, attr) { return obj[attr] = function() { var newValues; newValues = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (newValues.length === 0) { return obj['_' + attr]; } else { obj['_' + attr] = newValues[0]; obj.image.attr(attr, obj['_' + attr]); return obj; } }; }; Utils.timestamp = function() { return Date.now(); }; Utils.angle = function(a) { return 2 * Math.PI * a / 360; }; Utils.path_seg = function(p) { var a; a = p.pathSegTypeAsLetter; switch (a) { case 'M': case 'm': return [a, p.x, p.y].join(" "); case 'L': case 'l': return [a, p.x, p.y].join(" "); case 'A': case 'a': return [a, p.r, p.r, p.rot, p.c, p.d, p.x, p.y].join(" "); case 'C': case 'c': return [a, p.x1, p.y1, p.x2, p.y2, p.x, p.y].join(" "); case 'S': case 's': return [a, p.x2, p.y2, p.x, p.y].join(" "); case 'Q': case 'q': return [a, p.x1, p.y1, p.x, p.y].join(" "); case 'T': case 't': return [a, p.x, p.y].join(" "); case 'Z': case 'z': return a; } }; Utils.d = function(path) { var p; return ((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = path.length; _i < _len; _i++) { p = path[_i]; _results.push(this.path_seg(p)); } return _results; }).call(this)).join(" "); }; Utils.pathTween = function(d, i, a) { var interp, prec; prec = 4; interp = function(d, path) { var distances, dt, n0, n1, p, points; n0 = path.getTotalLength(); p = path.cloneNode(); p.setAttribute("d", d); n1 = p.getTotalLength(); distances = [0]; i = 0; dt = prec / Math.max(n0, n1); while ((i += dt) < 1) { distances.push(i); } distances.push(1); points = distances.map(function(t) { var p0, p1; p0 = path.getPointAtLength(t * n0); p1 = p.getPointAtLength(t * n1); return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]); }); return function(t) { if (t < 1) { return "M" + points.map(function(p) { return p(t); }).join("L"); } else { return d; } }; }; return interp(d, this); }; Utils.bilinear_interp = function(matrix, x, y) { var dxc, dxf, dyc, dyf, interp, tol, xc, xf, yc, yf; tol = 1e-100; xf = Math.floor(x); xc = Math.ceil(x + tol); yf = Math.floor(y); yc = Math.ceil(y + tol); dxf = x - xf; dxc = xc - x; dyf = y - yf; dyc = yc - y; interp = matrix[yf][xf] * dxc * dyc + matrix[yf][xc] * dxf * dyc + matrix[yc][xf] * dxc * dyf + matrix[yc][xc] * dxf * dyf; return interp; }; return Utils; })(); $z.Element = (function() { function Element(config) { this.config = config != null ? config : {}; this.d = $z.Factory.spawn($z.Vec); this.ri = $z.Factory.spawn($z.Vec); this.rj = $z.Factory.spawn($z.Vec); this.r_temp = $z.Factory.spawn($z.Vec); this.dr_temp = $z.Factory.spawn($z.Vec); this.line = $z.Factory.spawn($z.Vec); this.normal = $z.Factory.spawn($z.Vec); this.lshift = $z.Factory.spawn($z.Vec); this.vPar = $z.Factory.spawn($z.Vec); this.vPerp = $z.Factory.spawn($z.Vec); this.uPar = $z.Factory.spawn($z.Vec); this.uPerp = $z.Factory.spawn($z.Vec); this.dt = this.config.dt || 0.25; this.r = this.config.r || $z.Factory.spawn($z.Vec); this.dr = this.config.dr || $z.Factory.spawn($z.Vec); this.v = this.config.v || $z.Factory.spawn($z.Vec); this.f = this.config.f || $z.Factory.spawn($z.Vec); this.fcopy = $z.Utils.clone(this.config.f) || $z.Factory.spawn($z.Vec); this.force_param = this.config.force_param || []; this.size = this.config.size || 0; this.bb_width = this.config.bb_width || 0; this.bb_height = this.config.bb_height || 0; this.left = this.config.bb_width || 0; this.right = this.config.bb_height || 0; this.top = this.config.top || 0; this.bottom = this.config.bottom || 0; this.collision = this.config.collision || true; this.tol = this.config.tol || 0.25; this._stroke = this.config.stroke || "none"; this._fill = this.config.fill || "black"; this.angle = this.config.angle || 0; this.is_root = this.config.is_root || false; this.is_bullet = this.config.is_bullet || false; this.type = this.config.type || null; this.image = this.config.image || null; this.overlay = this.config.overlay || null; this.g = d3.select("#game_g").append("g").attr("transform", "translate(" + this.r.x + "," + this.r.y + ")").style('opacity', 0).datum(this); this.g = this.config.g || this.g; this.svg = this.config.svg || $z.Game.instance.svg; this.game_g = this.config.game_g || $z.Game.instance.g; this.quadtree = this.config.quadtree || null; this.tick = this.config.tick || $z.Physics.euler; this.is_removed = false; this.is_sleeping = false; this.is_flashing = false; this._cleanup = true; $z.Utils.addChainedAttributeAccessor(this, 'fill'); $z.Utils.addChainedAttributeAccessor(this, 'stroke'); } Element.prototype.reaction = function(element) { return element != null ? element.reaction() : void 0; }; Element.prototype.BB = function() { this.left = this.r.x - 0.5 * this.bb_width; this.right = this.r.x + 0.5 * this.bb_width; this.top = this.r.y - 0.5 * this.bb_height; return this.bottom = this.r.y + 0.5 * this.bb_height; }; Element.prototype.draw = function() { this.g.attr("transform", "translate(" + this.r.x + "," + this.r.y + ") rotate(" + (360 * 0.5 * this.angle / Math.PI) + ")"); }; Element.prototype.remove_check = function(n) { if (this.is_root || this.is_bullet) { this.reaction(n); return true; } return false; }; Element.prototype.offscreen = function() { return this.r.x < -this.size || this.r.y < -this.size || this.r.x > $z.Game.width + this.size || this.r.y > $z.Game.height + this.size; }; Element.prototype.fadeIn = function(dur, callback) { if (dur == null) { dur = 30; } if (dur != null) { return this.g.transition().duration(dur).ease('linear').style("opacity", 1).each('end', function(d) { return typeof callback === "function" ? callback(d) : void 0; }); } else { this.g.style("opacity", 1); return typeof callback === "function" ? callback(this) : void 0; } }; Element.prototype.fadeOut = function(dur, callback) { if (dur == null) { dur = 30; } return this.g.transition().duration(dur).ease('linear').style("opacity", 0).each('end', function(d) { return typeof callback === "function" ? callback(d) : void 0; }); }; Element.prototype.flash = function(dur, color, scaleFactor, initialOpacity) { if (dur == null) { dur = 1000; } if (color == null) { color = '#FFF'; } if (scaleFactor == null) { scaleFactor = 3; } if (initialOpacity == null) { initialOpacity = 0.4; } if (this.is_flashing) { return; } this.is_flashing = true; return this.overlay.style('fill', color).style('opacity', initialOpacity).transition().duration(dur).attr('transform', 'scale(' + scaleFactor + ')').style('opacity', 0).ease('linear').each('end', (function(_this) { return function() { _this.overlay.attr('transform', 'scale(1)'); return _this.is_flashing = false; }; })(this)); }; Element.prototype.start = function(duration, callback) { var index; if (duration == null) { duration = void 0; } if (callback == null) { callback = (function(_this) { return function() { return _this.collision = true; }; })(this); } if (this.is_sleeping) { console.log('element.start: is_sleeping... bug?'); return; } index = $z.Collision.list.indexOf(this); if (index === -1) { $z.Collision.list.push(this); } else { console.log('element.start: this element is already on the physics list! bug?'); } this.is_removed = false; this.draw(); this.fadeIn(duration, callback); }; Element.prototype.cleanup = function(_cleanup) { this._cleanup = _cleanup != null ? _cleanup : this._cleanup; if (this._cleanup && this.offscreen()) { return this.remove(); } }; Element.prototype.sleep = function() { $z.Factory.sleep(this); this.is_sleeping = true; }; Element.prototype.remove = function(dur) { if (dur == null) { dur = 30; } if (this.is_removed || !this.collision) { return; } this.collision = false; if (dur > 0) { this.fadeOut(dur, (function(d) { return d.is_removed = true; })); } else { this.is_removed = true; } }; Element.prototype.spawn = function() { this.wake(); this.start(); return this; }; Element.prototype.init = function() { this.r.x = 0; this.r.y = 0; this.dr.x = 0; this.dr.y = 0; this.v.x = 0; this.v.y = 0; this.f.x = 0; this.f.y = 0; return this; }; Element.prototype.wake = function(config) { this.is_sleeping = false; this.init(); if (config != null) { $z.Utils.set(this, config); } return this; }; Element.prototype.update = function(elapsedTime) { if (typeof this.tick === "function") { this.tick(this, elapsedTime); } this.draw(); }; Element.prototype.scale = function(scalingFactor, dur, callback) { if (scalingFactor == null) { scalingFactor = 10; } if (dur == null) { dur = void 0; } if (callback == null) { callback = function() {}; } if (dur != null) { return this.image.transition().duration(dur).ease('linear').attr('transform', 'scale(' + scalingFactor + ')').each('end', callback); } else { this.image.attr('transform', 'scale(' + scalingFactor + ')'); return callback(); } }; return Element; })(); $z.Game = (function() { var current_height, current_width, get_scale, image_preload_callback; Game.width = null; Game.height = null; Game.scale = 1; Game.audioSwitch = true; Game.musicSwitch = true; Game.instance = null; Game.message_color = "#FFF"; Game.width = 800; Game.height = 600; Game.maxdim = Math.max(Game.width, Game.height); function Game(config) { this.config = config != null ? config : {}; this.images_loaded = false; this.element = []; this.div = d3.select("#game_div"); this.svg = d3.select("#game_svg"); if (this.svg.empty()) { this.svg = this.div.append('svg').attr('id', 'game_svg'); } this.svg.attr("viewBox", '0 0 ' + $z.Game.width + ' ' + $z.Game.height).attr("preserveAspectRatio", "xMidYMin meet").attr('width', '100%').style('max-height', '100%'); this.scale = 1; this.g = d3.select("#game_g"); if (this.g.empty()) { this.g = this.svg.append('g'); } this.g.attr('id', 'game_g'); $z.Game.instance = this; $z.Game.instance.div.style('opacity', 0); this.preload_images(); } image_preload_callback = function() { var dur; $z.Game.instance.images_loaded = true; $z.Game.instance.start(); dur = 1000; return $z.Game.instance.div.transition().duration(dur).style('opacity', 1); }; Game.prototype.preload_images = function(image_list, preload_callback) { var dur; if (image_list == null) { image_list = $z.Game.instance.image_list; } if ((image_list != null) && (image_list.length != null) && image_list.length > 0) { return $z.ImageLoader.preload(image_list, image_preload_callback); } else { dur = 1000; return $z.Game.instance.div.transition().duration(dur).style('opacity', 1); } }; current_width = function(padding) { var element, x; if (padding == null) { padding = 8; } element = window.top.document.body; x = $(element).width(); x = Math.min(x, $(window).width()); x = Math.min(x, $(window.top).width()); if (x > padding && padding > 0) { return x = x - padding; } }; current_height = function(padding) { var element, y; if (padding == null) { padding = 124; } element = window.top; y = $(element).height(); if (y > padding && padding > 0) { y = y - padding; } return y; }; get_scale = function() { var max_scale, min_scale, r1, r2, scale; r1 = current_width() / $z.Game.width; r2 = current_height() / $z.Game.height; scale = r1 <= r2 ? r1 : r2; max_scale = 1.0; min_scale = 0.39; return scale = Math.max(min_scale, Math.min(max_scale, scale)); }; Game.prototype.start = function() { $z.Physics.start(); if (typeof Gameprez !== "undefined" && Gameprez !== null) { Gameprez.start(); } }; Game.prototype.stop = function(callback) { if (callback == null) { callback = function() {}; } this.cleanup(); $z.Physics.stop(); if (typeof Gameprez !== "undefined" && Gameprez !== null) { Gameprez.end($z.Gamescore.value, callback); } else { callback(); } }; Game.prototype.cleanup = function() { this.g.selectAll('g').each(function(d) { return d != null ? d.remove() : void 0; }); }; Game.prototype.message = function(txt, callback, dur) { var ready, spacing; if (dur == null) { dur = 1000; } callback || (callback = function() {}); this.g.selectAll('.game_message').remove(); spacing = 10; ready = this.g.append("text").attr('class', 'game_message').text(txt).attr("stroke", "none").attr("fill", $z.Game.message_color).attr("font-size", "36").attr("x", $z.Game.width / 2 - txt.length * spacing).attr("y", $z.Game.height / 2 + 20).attr('font-family', 'arial').attr('font-weight', 'bold').attr('opacity', 0).transition().duration(dur).style("opacity", 1).transition().duration(dur).style('opacity', 0).remove().each('end', callback); }; return Game; })(); $z.Circle = (function(_super) { __extends(Circle, _super); function Circle(config) { var _base; this.config = config != null ? config : {}; (_base = this.config).size || (_base.size = 15); Circle.__super__.constructor.call(this, this.config); this.type = 'Circle'; this.BB(); this.image = this.g.append("circle").attr("r", this.size).attr("x", 0).attr("y", 0); this.overlay = this.g.append("circle").style('opacity', 0).attr("r", this.size).attr("x", 0).attr("y", 0); this.stroke(this._stroke); this.fill(this._fill); } Circle.prototype.draw = function() { Circle.__super__.draw.apply(this, arguments); return this.image.attr("r", this.size); }; Circle.prototype.BB = function(size) { this.size = size != null ? size : this.size; this.bb_width = 2 * this.size; this.bb_height = 2 * this.size; return Circle.__super__.BB.apply(this, arguments); }; return Circle; })($z.Element); $z.Polygon = (function(_super) { __extends(Polygon, _super); function Polygon(config) { this.config = config != null ? config : {}; Polygon.__super__.constructor.call(this, this.config); this.type = 'Polygon'; this.path = this.config.path || this.default_path(); this.image = this.g.append("path"); this.overlay = this.g.append("path").style('opacity', 0).attr("x", 0).attr("y", 0); this.fill(this._fill); this.stroke(this._stroke); this.set_path(); } Polygon.prototype.default_path = function() { var invsqrt3; invsqrt3 = 1 / Math.sqrt(3); return [ { pathSegTypeAsLetter: 'M', x: -this.size, y: this.size * invsqrt3, react: true }, { pathSegTypeAsLetter: 'L', x: 0, y: -2 * this.size * invsqrt3, react: true }, { pathSegTypeAsLetter: 'L', x: this.size, y: this.size * invsqrt3, react: true }, { pathSegTypeAsLetter: 'Z' } ]; }; Polygon.prototype.d_attr = function() { return $z.Utils.d(this.path); }; Polygon.prototype.polygon_path = function() { var i, _i, _ref; for (i = _i = 0, _ref = this.path.length - 2; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { this.path[i].r = $z.Factory.spawn($z.Vec, this.path[i]).subtract(this.path[(i + 1) % (this.path.length - 1)]); this.path[i].n = $z.Factory.spawn($z.Vec, { x: -this.path[i].r.y, y: this.path[i].r.x }).normalize(); } this.BB(); }; Polygon.prototype.set_path = function(path) { var i, maxd, maxnode, node, _i, _ref; this.path = path != null ? path : this.path; this.pathref = this.path.map(function(d) { return $z.Utils.clone(d); }); this.polygon_path(); maxnode = this.path[0]; this.path[0].d = maxnode.x * maxnode.x + maxnode.y * maxnode.y; maxd = this.path[0].d; for (i = _i = 1, _ref = this.path.length - 2; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { node = this.path[i]; node.d = node.x * node.x + node.y * node.y; if (node.d > maxd) { maxnode = this.path[i]; } } this.maxnode = $z.Factory.spawn($z.Vec, maxnode); this.size = this.maxnode.length(); this.image.attr("d", this.d_attr()); return this.overlay.attr("d", this.d_attr()); }; Polygon.prototype.BB = function() { var i, xmax, xmin, ymax, ymin, _i, _ref; xmax = this.path[0].x; ymax = this.path[0].y; xmin = xmax; ymin = ymax; for (i = _i = 1, _ref = this.path.length - 1; 1 <= _ref ? _i < _ref : _i > _ref; i = 1 <= _ref ? ++_i : --_i) { if (this.path[i].x > xmax) { xmax = this.path[i].x; } if (this.path[i].x < xmin) { xmin = this.path[i].x; } if (this.path[i].y > ymax) { ymax = this.path[i].y; } if (this.path[i].y < ymin) { ymin = this.path[i].y; } } this.bb_width = xmax - xmin; this.bb_height = ymax - ymin; return Polygon.__super__.BB.apply(this, arguments); }; Polygon.prototype.rotate_path = function() { var c, i, s, seg, _i, _ref; for (i = _i = 0, _ref = this.path.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { seg = this.path[i]; if (seg.x == null) { continue; } c = Math.cos(this.angle); s = Math.sin(this.angle); seg.x = c * this.pathref[i].x - s * this.pathref[i].y; seg.y = s * this.pathref[i].x + c * this.pathref[i].y; } this.polygon_path(); }; return Polygon; })($z.Element); $z.Collision = (function() { var circle_circle_dist, circle_lineseg_dist, lineseg_intersect, name, nearest_node, sort, z_check; function Collision() {} Collision.use_bb = false; Collision.list = []; Collision.update_quadtree = function(force_update) { var data; if (force_update == null) { force_update = false; } if (!(this.list.length > 0)) { return; } data = this.list.filter(function(d) { return d.collision; }).map(function(d) { return { x: d.r.x, y: d.r.y, d: d }; }); return this.quadtree = d3.geom.quadtree(data); }; Collision.quadtree = Collision.update_quadtree(); Collision.resolve = function(m, n) { var iter, maxiter, reaction, _results; maxiter = 32; iter = 1; reaction = false; _results = []; while ($z.Collision.check(m, n, reaction) && iter <= maxiter) { m.tick(); n.tick(); _results.push(iter++); } return _results; }; Collision.detect = function() { var d, i, length, size, x0, x3, y0, y3, _results; if (!(this.list.length > 0)) { return; } this.update_quadtree(); length = this.list.length; i = 0; _results = []; while (i < length) { d = this.list[i]; if (d.collision) { size = 2 * (d.size + d.tol); x0 = d.r.x - size; x3 = d.r.x + size; y0 = d.r.y - size; y3 = d.r.y + size; this.quadtree.visit(function(node, x1, y1, x2, y2) { var p; p = node.point; if (p !== null) { if (p.is_removed) { return false; } if (!(d !== p.d && p.d.collision)) { return false; } if ((p.x >= x0) && (p.x < x3) && (p.y >= y0) && (p.y < y3)) { $z.Collision.check(d, p.d); } } return x1 >= x3 || y1 >= y3 || x2 < x0 || y2 < y0; }); } length = this.list.length; _results.push(i++); } return _results; }; name = [null, null]; sort = [null, null]; Collision.check = function(ei, ej, reaction) { var collision, d, m, n, reaction_type; if (reaction == null) { reaction = true; } name[0] = ei.type; name[1] = ej.type; sort[0] = ei.type; sort[1] = ej.type; sort.sort(); if (name[0] === sort[0] && name[1] === sort[1]) { m = ei; n = ej; } else { m = ej; n = ei; } m.d.collision = false; n.d.collision = false; switch (m.type) { case 'Circle': switch (n.type) { case 'Circle': d = this.circle_circle(m, n); reaction_type = 'circle_circle'; break; case 'Polygon': d = this.circle_polygon(m, n); reaction_type = 'circle_polygon'; } break; case 'Polygon': switch (n.type) { case 'Polygon': d = this.polygon_polygon(m, n); reaction_type = 'polygon_polygon'; } } if (d.collision && reaction) { $z.Reaction[reaction_type](m, n, d); } collision = d.collision; return collision; }; Collision.rectangle_rectangle = function(m, n) { var not_intersect; m.BB(); n.BB(); not_intersect = n.left > m.right || n.right < m.left || n.top > m.bottom || n.bottom < m.top; return !not_intersect; }; Collision.circle_circle = function(m, n) { var d; if (this.use_bb) { if (this.rectangle_rectangle(m, n)) { d = circle_circle_dist(m, n); d.collision = true; } else { d = { collision: false }; } } else { d = circle_circle_dist(m, n); d.collision = d.dist <= d.dmin ? true : false; } return d; }; Collision.circle_polygon = function(circle, polygon) { var d, i, _i, _ref; if (this.use_bb) { if (this.rectangle_rectangle(circle, polygon)) { i = nearest_node(polygon, circle); d = circle_lineseg_dist(circle, polygon, i); d.i = i; d.collision = true; } else { d = { collision: false }; } } else { for (i = _i = 0, _ref = polygon.path.length - 2; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { if (!polygon.path[i].react) { continue; } d = circle_lineseg_dist(circle, polygon, i); if (d.dist > circle.size) { continue; } d.i = i; d.collision = true; break; } } return d; }; Collision.polygon_polygon = function(m, n) { var d, i, j, _i, _j, _ref, _ref1; if (this.use_bb) { if (this.rectangle_rectangle(m, n)) { d = circle_circle_dist(m, n); d.i = nearest_node(m, n); d.j = nearest_node(n, m); d.collision = true; } else { d = { collision: false }; } } else { d = circle_circle_dist(m, n); d.collision = false; if (d.dist <= d.dmin) { for (i = _i = 0, _ref = m.path.length - 2; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { for (j = _j = 0, _ref1 = n.path.length - 2; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; j = 0 <= _ref1 ? ++_j : --_j) { if (!lineseg_intersect(m, n, i, j)) { continue; } d.i = i; d.j = j; d.collision = true; break; } if (d.collision) { break; } } } } return d; }; nearest_node = function(m, n) { var d, i, nn, nnd, node, _i, _ref; nn = m.path[0]; nnd = (nn.x + m.r.x - n.r.x) * (nn.x + m.r.x - n.r.x) + (nn.y + m.r.y - n.r.y) * (nn.y + m.r.y - n.r.y); for (i = _i = 1, _ref = this.path.length - 2; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { node = m.path[i]; d = (node.x + m.r.x - n.r.x) * (node.x + m.r.x - n.r.x) + (node.y + m.r.y - n.r.y) * (node.y + m.r.y - n.r.y); if (d < nnd) { nn = m.path[i]; } } return m.path.indexOf(nn); }; circle_circle_dist = function(m, n) { var d; d = m.d.init(m.r).subtract(n.r); d.dist = Math.sqrt(d.x * d.x + d.y * d.y); d.dmin = m.size + n.size; return d; }; circle_lineseg_dist = function(circle, polygon, i) { var d, dr, r, ri, rj, rr, t; ri = polygon.path[i]; rj = circle.rj.init(z_check(polygon.path, i)); r = circle.r_temp.init(circle.rj).subtract(ri); rr = r.x * r.x + r.y * r.y; dr = circle.dr_temp.init(circle.r).subtract(ri).subtract(polygon.r); t = (r.x * dr.x + r.y * dr.y) / rr; if (t < 0) { } else if (t > 1) { dr.x = circle.r.x - rj.x - polygon.r.x; dr.y = circle.r.y - rj.y - polygon.r.y; } else { dr.x = r.x * t + ri.x + polygon.r.x; dr.y = r.y * t + ri.y + polygon.r.y; dr.x *= -1; dr.y *= -1; dr.x += circle.r.x; dr.y += circle.r.y; } d = circle.d.init(dr); d.t = t; d.r = [r.x, r.y]; d.rr = rr; d.dist = Math.sqrt(dr.x * dr.x + dr.y * dr.y); return d; }; lineseg_intersect = function(m, n, i, j) { var A1, A2, B1, B2, C1, C2, check1, check2, check3, check4, det, ri, rj, si, sj, x, y, _ref, _ref1, _ref2, _ref3; ri = m.ri.init(m.path[i]); rj = m.rj.init(z_check(m.path, i)); si = n.ri.init(n.path[j]); sj = n.rj.init(z_check(n.path, j)); A1 = rj.y - ri.y; B1 = ri.x - rj.x; C1 = A1 * (ri.x + m.r.x) + B1 * (ri.y + m.r.y); A2 = sj.y - si.y; B2 = si.x - sj.x; C2 = A2 * (si.x + n.r.x) + B2 * (si.y + n.r.y); det = A1 * B2 - A2 * B1; if (det === 0) { return false; } x = (B2 * C1 - B1 * C2) / det; y = (A1 * C2 - A2 * C1) / det; check1 = (Math.min(ri.x, rj.x) - m.tol <= (_ref = x - m.r.x) && _ref <= Math.max(ri.x, rj.x) + m.tol); check2 = (Math.min(si.x, sj.x) - n.tol <= (_ref1 = x - n.r.x) && _ref1 <= Math.max(si.x, sj.x) + n.tol); check3 = (Math.min(ri.y, rj.y) - m.tol <= (_ref2 = y - m.r.y) && _ref2 <= Math.max(ri.y, rj.y) + m.tol); check4 = (Math.min(si.y, sj.y) - n.tol <= (_ref3 = y - n.r.y) && _ref3 <= Math.max(si.y, sj.y) + n.tol); if (check1 && check2 && check3 && check4) { return true; } else { return false; } }; z_check = function(seg, i) { switch (seg[i + 1].pathSegTypeAsLetter) { case 'z': case 'Z': return seg[0]; default: return seg[i + 1]; } }; return Collision; })(); $z.Force = (function() { function Force() {} Force.dr = { x: 0, y: 0 }; Force.rpx = { x: 0, y: 0 }; Force.rmx = { x: 0, y: 0 }; Force.rpy = { x: 0, y: 0 }; Force.rmy = { x: 0, y: 0 }; Force["eval"] = function(element, param, f, accumulateSwitch) { var emx, emy, epx, epy, fx, fy, r2, r3; if (accumulateSwitch == null) { accumulateSwitch = false; } if ((param != null ? param.type : void 0) == null) { console.log('Force.eval: undefined param type, param:', param); f.x = 0; f.y = 0; return f; } switch (param.type) { case 'constant': fx = param.fx; fy = param.fy; break; case 'friction': fx = -param.alpha * element.v.x; fy = -param.alpha * element.v.y; break; case 'spring': fx = -(element.r.x - param.cx); fy = -(element.r.y - param.cy); break; case 'charge': case 'gravity': this.dr.x = param.cx - element.r.x; this.dr.y = param.cy - element.r.y; r2 = this.dr.x * this.dr.x + this.dr.y * this.dr.y; r3 = r2 * Math.sqrt(r2); fx = param.q * this.dr.x / r3; fy = param.q * this.dr.y / r3; break; case 'random': fx = 2 * (Math.random() - 0.5) * param.xScale; fy = 2 * (Math.random() - 0.5) * param.yScale; if (element.r.x > param.xBound) { fx = -param.fxBound; } if (element.r.y > param.yBound) { fy = -param.fyBound; } if (element.r.x < 0) { fx = param.fxBound; } if (element.r.y < 0) { fy = param.fyBound; } break; case 'gradient': this.rpx.x = element.r.x; this.rpx.y = element.r.y; this.rpx.x += param.tol; this.rmx.x = element.r.x; this.rmx.y = element.r.y; this.rmx.x -= param.tol; this.rpy.x = element.r.x; this.rpy.y = element.r.y; this.rpy.y += param.tol; this.rmy.x = element.r.x; this.rmy.y = element.r.y; this.rmy.y -= param.tol; epx = param.energy(this.rpx); emx = param.energy(this.rmx); epy = param.energy(this.rpy); emy = param.energy(this.rmy); if (!((epx != null) && (emx != null) && (epy != null) && (emy != null))) { fx = 0; fy = 0; break; } fx = -0.5 * (epx - emx) / param.tol; fy = -0.5 * (epy - emy) / param.tol; } if (accumulateSwitch) { f.x += fx; f.y += fy; } else { f.x = fx; f.y = fy; } return f; }; return Force; })(); $z.Physics = (function() { function Physics() {} Physics.fps = 240; Physics.elapsedTime = 0; Physics.tick = 1000 / Physics.fps; Physics.off = true; Physics.game = null; Physics.callbacks = []; Physics.debug = false; Physics.timestamp = void 0; Physics.paused = false; Physics.euler = function(element, dt) { var accumulateSwitch; if (dt == null) { dt = Physics.tick; } if (element.cleanup()) { return; } element.f.x = 0; element.f.y = 0; accumulateSwitch = true; element.force_param.forEach(function(param) { return $z.Force["eval"](element, param, element.f, accumulateSwitch); }); element.v.add(element.f.scale(dt)); element.dr.init(element.v).scale(dt); element.r.add(element.dr); }; Physics.integrate = function(t) { var elapsedTime, fps; if (Physics.off) { return true; } elapsedTime = t - Physics.timestamp; Physics.elapsedTime = elapsedTime; if (Physics.debug) { fps = 1000 / elapsedTime; console.log('Physics.integrate:', 'dt: ', elapsedTime, 't: ', t, 'timestamp: ', Physics.timestamp, 'dt_chk: ', t - Physics.timestamp, 'fps: ' + fps); } Physics.timestamp = t; Physics.update(elapsedTime); return Physics.off; }; Physics.update = function(elapsedTime) { var Nmax, Nstep, dur, step; if (elapsedTime == null) { elapsedTime = Physics.elapsedTime; } Nstep = 2; Nmax = 600; if (Nstep > Nmax) { dur = 2000; Physics.stop(); $z.Game.instance.message('CPU SPEED ERROR', function() { return $z.Game.instance.stop(); }, dur); } step = 0; while (step < Nstep) { Physics.step(); $z.Collision.detect(); Physics.run_callbacks(); ++step; } return Physics.run_callbacks(); }; Physics.step = function(elapsedTime) { var index, _results; if (elapsedTime == null) { elapsedTime = Physics.tick; } index = $z.Collision.list.length; _results = []; while (index--) { if ($z.Collision.list[index].is_removed) { _results.push($z.Utils.index_pop($z.Collision.list, index).sleep()); } else { $z.Collision.list[index].update(elapsedTime); if (Physics.debug) { _results.push(console.log('Physics.update', 'index:', index, 'fps:', fps, 'r.x:', $z.Collision.list[index].r.x, 'r.y:', $z.Collision.list[index].r.y)); } else { _results.push(void 0); } } } return _results; }; Physics.run_callbacks = function() { var bool, index, _results; index = Physics.callbacks.length; _results = []; while (index--) { if (Physics.callbacks.length === 0) { break; } bool = Physics.callbacks[index](Physics.timestamp); if (bool) { _results.push($z.Utils.index_pop(Physics.callbacks, index)); } else { _results.push(void 0); } } return _results; }; Physics.start = function() { var blurCallback; if (!Physics.off) { return; } Physics.off = false; Physics.timestamp = 0; d3.timer(Physics.integrate); blurCallback = function() { Physics.paused = true; return Physics.stop(); }; $(window).blur(null); $(window).focus(null); $(window).blur(blurCallback); $(window).focus(function() { if (!Physics.off) { return; } Physics.paused = false; if ($z.Gamescore.lives >= 0) { return $z.Game.instance.message('GET READY', function() { if (Physics.paused) { return; } Physics.timestamp = 0; return Physics.start(); }); } }); }; Physics.stop = function() { if (Physics.off) { return; } Physics.off = true; Physics.timestamp = void 0; setTimeout(Physics.update, 2 * Physics.tick); }; return Physics; })(); $z.Reaction = (function() { function Reaction() {} Reaction.circle_circle = function(m, n, d) { var line, overstep, shift; if (m.remove_check(n) || n.remove_check(m)) { return; } line = m.line.init(d).normalize(); overstep = Math.max(d.dmin - d.dist, 0); shift = 0.5 * (Math.max(m.tol, n.tol) + overstep); $z.Reaction.elastic_collision(m, n, line, shift); m.reaction(n); }; Reaction.circle_polygon = function(circle, polygon, d) { var intersecting_segment, normal, shift; if (circle.remove_check(polygon) || polygon.remove_check(circle)) { return; } intersecting_segment = polygon.path[d.i]; normal = intersecting_segment.n; shift = 0.5 * Math.max(circle.tol, polygon.tol); $z.Reaction.elastic_collision(circle, polygon, normal, shift); }; Reaction.polygon_polygon = function(m, n, d) { var dot_a, dot_b, mseg, normal, nseg, segj, shift; if (m.remove_check(n) || n.remove_check(m)) { return; } mseg = m.path[d.i]; nseg = n.path[d.j]; dot_a = mseg.n.dot(d); dot_b = nseg.n.dot(d); if (Math.abs(dot_a) > Math.abs(dot_b)) { normal = m.normal.init(mseg.n).scale(dot_a / Math.abs(dot_a)); segj = nseg; } else { normal = m.normal.init(nseg.n).scale(dot_b / Math.abs(dot_b)); segj = mseg; } shift = 0.5 * Math.max(m.tol, n.tol); $z.Reaction.elastic_collision(m, n, normal, shift); m.reaction(n); }; Reaction.elastic_collision = function(m, n, line, shift) { var cPar, dPar, iter, lshift, maxiter, reaction, uPar, uPerp, vPar, vPerp; lshift = m.lshift.init(line).scale(shift); maxiter = 32; iter = 1; reaction = false; while ($z.Collision.check(m, n, reaction) && iter <= maxiter) { m.r = m.r.add(lshift); n.r = n.r.subtract(lshift); iter++; } cPar = m.v.dot(line); vPar = m.vPar.init(line).scale(cPar); vPerp = m.vPerp.init(m.v).subtract(vPar); dPar = n.v.dot(line); uPar = m.uPar.init(line).scale(dPar); uPerp = m.uPerp.init(n.v).subtract(uPar); uPar.add(vPerp); vPar.add(uPerp); m.v.x = uPar.x; m.v.y = uPar.y; n.v.x = vPar.x; n.v.y = vPar.y; }; return Reaction; })(); $z.ForceParam = (function() { function ForceParam(config) { this.config = config != null ? config : {}; this.type = this.config.type || 'constant'; switch (this.type) { case 'constant': this.fx = this.config.x || 0; this.fy = this.config.y || 0; break; case 'friction': this.alpha = this.config.alpha || 1; this.vscale = this.config.vscale || .99; this.vcut = this.config.vcut || 1e-2; break; case 'spring': this.cx = this.config.cx || 0; this.cy = this.config.cy || 0; break; case 'charge': case 'gravity': this.cx = this.config.cx || 0; this.cy = this.config.cy || 0; this.q = this.config.q || 1; break; case 'random': this.xScale = this.config.xScale || 1; this.yScale = this.config.yScale || 1; this.fxBound = this.config.fxBound || 10; this.fyBound = this.config.fyBound || 10; break; case 'gradient': this.tol = this.config.tol || 0.1; this.energy = this.config.energy || function(r) {}; } } return ForceParam; })(); $z.Vec = (function() { function Vec(config) { this.config = config != null ? config : {}; this.x = this.config.x || 0; this.y = this.config.y || 0; } Vec.prototype.init = function(v) { if (v == null) { v = { x: 0, y: 0 }; } this.x = v.x; this.y = v.y; return this; }; Vec.prototype.scale = function(c) { this.x *= c; this.y *= c; return this; }; Vec.prototype.add = function(v) { this.x += v.x; this.y += v.y; return this; }; Vec.prototype.subtract = function(v) { this.x -= v.x; this.y -= v.y; return this; }; Vec.prototype.rotate = function(a) { var c, s; c = Math.cos(a); s = Math.sin(a); this.x = c * this.x - s * this.y; this.y = s * this.x + c * this.y; return this; }; Vec.prototype.dot = function(v) { return this.x * v.x + this.y * v.y; }; Vec.prototype.length_squared = function() { return this.dot(this); }; Vec.prototype.length = function() { return Math.sqrt(this.length_squared()); }; Vec.prototype.normalize = function(length) { var inverseLength; if (length == null) { length = 1; } inverseLength = length / this.length(); this.x *= inverseLength; this.y *= inverseLength; return this; }; Vec.prototype.dist_squared = function(v) { var dx, dy; dx = this.x - v.x; dy = this.y - v.y; return dx * dx + dy * dy; }; Vec.prototype.dist = function(v) { return Math.sqrt(this.dist_squared(v)); }; return Vec; })(); $z.Drop = (function(_super) { __extends(Drop, _super); function Drop(config) { var dur; this.config = config != null ? config : {}; this.config.size = this.config.size || .6; Drop.__super__.constructor.call(this, this.config); this.fill('navy'); this.stroke('none'); this.image.attr('opacity', '0.6'); this.lifetime = $z.Utils.timestamp(); this.max_lifetime = 2e4; this.fadeIn(dur = 250); } Drop.prototype.init = function() { this.lifetime = $z.Utils.timestamp(); return Drop.__super__.init.apply(this, arguments); }; Drop.prototype.cleanup = function() { this.lifetime = $z.Utils.timestamp() - this.lifetime; if (this.lifetime > this.max_lifetime) { this.remove(); } this.lifetime = $z.Utils.timestamp() - this.lifetime; if (this.offscreen()) { if (this.r.x > $z.Game.width) { this.r.x = this.r.x % $z.Game.width; } if (this.r.x < 0) { this.r.x = $z.Game.width + this.r.x; } if (this.r.y < 0) { this.r.y = 0; this.v.y = Math.abs(this.v.y); this.r.x = (this.r.x + $z.Game.width * 0.5) % $z.Game.width; } if (this.r.y > $z.Game.height) { this.r.y = $z.Game.height; this.v.y = -Math.abs(this.v.y); this.r.x = (this.r.x + $z.Game.width * 0.5) % $z.Game.width; } } }; return Drop; })($z.Circle); $z.Rainflow = (function(_super) { __extends(Rainflow, _super); function Rainflow(config) { var V, drops, dur, inst, prompt; this.config = config != null ? config : {}; this.drop = __bind(this.drop, this); $z.Game.height = 180; $z.Game.width = 360; Rainflow.__super__.constructor.apply(this, arguments); this.map_width = 360; this.map_height = 180; this.image = this.g.append('image').attr('xlink:href', 'earth_elevation6.png').attr('height', this.map_height).attr('width', this.map_width); this.root = $z.Factory.spawn($z.Root); this.numel = this.config.numel || 20; this.elevation = []; this.lastdrop = $z.Utils.timestamp(); this.raining = false; drops = (function(_this) { return function(text) { var row; row = text.split('\n'); _this.elevation = row.map(function(d) { return d.split(',').map(function(d) { return Number(d); }); }); _this.elevation.pop(); _this.gravity_param = { tol: 1, energy: V, type: 'gradient' }; _this.friction_param = { alpha: .02, type: 'friction' }; _this.svg.on("click", _this.drop); return _this.start(); }; })(this); prompt = this.g.append("text").text("").attr("stroke", "black").attr("fill", "deepskyblue").attr("font-size", "36").attr("x", this.map_width / 2 - 100).attr("y", this.map_height / 4).attr('font-family', 'arial').attr('font-weight', 'bold').attr('opacity', 0); prompt.text("RAINFLOW"); dur = 1500; prompt.transition().duration(dur).attr('opacity', 1).transition().duration(dur).delay(dur).attr('opacity', 0).remove(); inst = this.g.append("text").text("").attr("stroke", "none").attr("fill", "white").attr("font-size", 10).attr("x", this.map_width / 2 - 45).attr("y", this.map_height / 4 + 40).attr('font-family', 'arial').attr('font-weight', 'bold').attr('opacity', 0); inst.text("click to make it rain"); inst.transition().duration(dur).attr('opacity', 1).transition().duration(dur).attr('opacity', 0).remove().each('end', function() { return d3.text('topo_flip.csv', drops); }); V = (function(_this) { return function(r) { var energy, scale, x, y; x = r.x; y = r.y; if (x < 0) { x = _this.elevation[0].length - 1 + x % (_this.elevation[0].length - 1); } if (x > _this.elevation[0].length - 1) { x = x % (_this.elevation[0].length - 1); } if (y < 0) { y = _this.elevation.length - 1 + y % (_this.elevation.length - 1); } if (y > _this.elevation.length - 1) { y = y % (_this.elevation.length - 1); } scale = 1e-6; energy = scale * $z.Utils.bilinear_interp(_this.elevation, x, y); return energy; }; })(this); } Rainflow.prototype.drop = function(r) { var clear, config, dr, dur, i, int, new_drop, stamp, _i, _ref; if (r == null) { r = this.root.r; } stamp = $z.Utils.timestamp(); if (this.raining) { return; } this.raining = true; this.lastdrop = stamp; config = []; for (i = _i = 0, _ref = this.numel - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { dr = $z.Factory.spawn($z.Vec, { x: 2 * this.root.size * (Math.random() - 0.5), y: 2 * this.root.size * (Math.random() - 0.5) }); config.push({ r: $z.Factory.spawn($z.Vec, r).add(dr), force_param: [$z.Factory.spawn($z.ForceParam, this.gravity_param), $z.Factory.spawn($z.ForceParam, this.friction_param)], width: this.map_width, height: this.map_height }); } if (!(config.length > 0)) { return; } dur = 10; new_drop = function() { $z.Factory.spawn($z.Drop, config.pop()).start(); if (config.length === 0) { console.log('clearing'); clear(); return $z.Game.instance.raining = false; } }; int = setInterval(new_drop, dur); return clear = function() { return clearInterval(int); }; }; return Rainflow; })($z.Game); $(document).ready(function() { return new $z.Rainflow(); }); $z.Root = (function(_super) { __extends(Root, _super); function Root(config) { this.config = config != null ? config : {}; this.move = __bind(this.move, this); this.config.size = this.config.size || 1.5; Root.__super__.constructor.call(this, this.config); this.svg.style("cursor", "none"); this.fill('none'); this.stroke('navy'); this.image.attr('opacity', 0.4).attr('stroke-width', 1); this.svg.on("mousemove", this.move); this.is_root = true; this.tick = function() {}; this.g.style('opacity', 1); } Root.prototype.move = function(node) { var xy; if (node == null) { node = this.svg.node(); } xy = d3.mouse(node); this.r.x = xy[0]; this.r.y = xy[1]; return this.draw(); }; return Root; })($z.Circle); }).call(this); -
dannyko created this gist
Sep 13, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,3 @@ Rainflow Gradient flow example using bilinear interpolation of matrix map of Earth altitudes