Last active
September 3, 2015 15:29
-
-
Save asnapper/8821309 to your computer and use it in GitHub Desktop.
Revisions
-
asnapper revised this gist
Feb 5, 2014 . 1 changed file with 325 additions and 0 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 @@ -0,0 +1,325 @@ // ==UserScript== // @id fly-links@fly // @name IITC plugin: Fly Links // @category Layer // @version 0.2.1.20140205.104258 // @updateURL none // @downloadURL none // @description [local-2014-02-05-104258] Calculate how to link the portals to create the largest tidy set of nested fields. Enable from the layer chooser. // @include https://www.ingress.com/intel* // @include http://www.ingress.com/intel* // @match https://www.ingress.com/intel* // @match http://www.ingress.com/intel* // @grant none // ==/UserScript== function wrapper(plugin_info) { // ensure plugin framework is there, even if iitc is not yet loaded if(typeof window.plugin !== 'function') window.plugin = function() {}; //PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!! //(leaving them in place might break the 'About IITC' page or break update checks) plugin_info.buildName = 'local'; plugin_info.dateTimeVersion = '20140205.104258'; plugin_info.pluginId = 'fly-links'; //END PLUGIN AUTHORS NOTE // PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.flyLinks = function() {}; // const values window.plugin.flyLinks.MAX_PORTALS_TO_OBSERVE = 1000; window.plugin.flyLinks.MAX_PORTALS_TO_LINK = 100; // zoom level used for projecting points between latLng and pixel coordinates. may affect precision of triangulation window.plugin.flyLinks.PROJECT_ZOOM = 16; window.plugin.flyLinks.linksLayerGroup = null; window.plugin.flyLinks.fieldsLayerGroup = null; window.plugin.flyLinks.updateLayer = function() { if (!window.map.hasLayer(window.plugin.flyLinks.linksLayerGroup) && !window.map.hasLayer(window.plugin.flyLinks.fieldsLayerGroup)) return; window.plugin.flyLinks.linksLayerGroup.clearLayers(); window.plugin.flyLinks.fieldsLayerGroup.clearLayers(); var ctrl = [$('.leaflet-control-layers-selector + span:contains("Fly links")').parent(), $('.leaflet-control-layers-selector + span:contains("Fly fields")').parent()]; if (Object.keys(window.portals).length > window.plugin.flyLinks.MAX_PORTALS_TO_OBSERVE) { $.each(ctrl, function(guid, ctl) {ctl.addClass('disabled').attr('title', 'Too many portals: ' + Object.keys(window.portals).length);}); return; } var locations = []; var bounds = map.getBounds(); $.each(window.portals, function(guid, portal) { var ll = portal.getLatLng(); if (bounds.contains(ll)) { var p = map.project(portal.getLatLng(), window.plugin.flyLinks.PROJECT_ZOOM); if (!window.plugin.disablePortal || !(guid in window.plugin.disablePortal.disabledGUID)) locations.push(p); } }); var distance = function(a, b) { return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }; var drawLink = function(a, b, style) { var alatlng = map.unproject(a, window.plugin.flyLinks.PROJECT_ZOOM); var blatlng = map.unproject(b, window.plugin.flyLinks.PROJECT_ZOOM); var poly = L.polyline([alatlng, blatlng], style); poly.addTo(window.plugin.flyLinks.linksLayerGroup); } var drawField = function(a, b, c, style) { var alatlng = map.unproject(a, window.plugin.flyLinks.PROJECT_ZOOM); var blatlng = map.unproject(b, window.plugin.flyLinks.PROJECT_ZOOM); var clatlng = map.unproject(c, window.plugin.flyLinks.PROJECT_ZOOM); var poly = L.polygon([alatlng, blatlng, clatlng], style); poly.addTo(window.plugin.flyLinks.fieldsLayerGroup); } if (locations.length > window.plugin.flyLinks.MAX_PORTALS_TO_LINK) { $.each(ctrl, function(guid, ctl) {ctl.addClass('disabled').attr('title', 'Too many portals (linked/observed): ' + locations.length + '/' + Object.keys(window.portals).length);}); return; } $.each(ctrl, function(guid, ctl) {ctl.removeClass('disabled').attr('title', 'portals (linked/observed): ' + locations.length + '/' + Object.keys(window.portals).length);}); var EPS = 1e-9; var det = function(a, b, c) { return a.x * b.y - a.y * b.x + b.x * c.y - b.y * c.x + c.x * a.y - c.y * a.x; } var convexHull = function(points) { if (points.length < 3) return []; var result = []; var func = function _func(ai, bi, index) { var maxd = 0; var maxdi = -1; var a = points[ai]; var b = points[bi]; var _index = []; for (var i = 0; i < index.length; ++i) { var c = points[index[i]]; var d = -det(a, b, c); if (d > EPS) { _index.push(index[i]); } if (maxd < d - EPS) { maxd = d; maxdi = index[i]; } } if (maxdi != -1) { _func(ai, maxdi, _index); _func(maxdi, bi, _index); } else { result.push(ai); } } var minxi = 0; var maxxi = 0; var index = []; for (var i = 0; i < points.length; ++i) { index.push(i); if (points[minxi].x > points[i].x) minxi = i; if (points[maxxi].x < points[i].x) maxxi = i; } func(minxi, maxxi, index); func(maxxi, minxi, index); return result; } var index = convexHull(locations); var triangulate = function(index, locations) { if (index.length == 0) return {edges: [], triangles: []}; var data = []; var subtriangulate = function _subtriangulate(ai, bi, ci, index) { var _i = [ai, bi, ci].sort(function(a,b){return a-b;}); if (data[_i[0]] === undefined) data[_i[0]] = []; if (data[_i[0]][_i[1]-_i[0]] === undefined) data[_i[0]][_i[1]-_i[0]] = []; if (data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]] === undefined) { var _index = []; for (var i = 0; i < index.length; ++i) { var detc = det(locations[ai], locations[bi], locations[index[i]]); var deta = det(locations[bi], locations[ci], locations[index[i]]); var detb = det(locations[ci], locations[ai], locations[index[i]]); if (deta > EPS && detb > EPS && detc > EPS) { _index.push(index[i]); } } var besth = 0; var besthi = -1; if (_index.length == 0) { var a = locations[ai]; var b = locations[bi]; var c = locations[ci]; var s = Math.abs(det(a, b, c)); var ch = s / distance(a, b); var ah = s / distance(b, c); var bh = s / distance(c, a); besth = Math.min(ah, bh, ch); besthi = -1; } else { var besths = 0; for (var i = 0; i < _index.length; ++i) { var ch = _subtriangulate(ai, bi, _index[i], _index); var ah = _subtriangulate(bi, ci, _index[i], _index); var bh = _subtriangulate(ci, ai, _index[i], _index); var _besth = Math.min(ah, bh, ch); var _besths = ah + bh + ch; if (besth < _besth || Math.abs(besth - _besth) <= EPS && besths < _besths) { besth = _besth; besths = _besths; besthi = _index[i]; } } } data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]] = {height: besth, index: besthi}; } return data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].height; } var subindex = []; for (var i = 0; i < locations.length; ++i) { subindex.push(i); } var best = []; for (var len = 1; len <= index.length - 1; ++len) { best[len] = []; for (var k = 0; k < index.length - len; ++k) { var t = 0; var tlen = -1; for (var _len = 1; _len <= len - 1; ++_len) { var _t = 0; $.each([best[_len][k].height, best[len-_len][k+_len].height, subtriangulate(index[k], index[k+_len], index[k+len], subindex)], function(guid, __t) { if (__t == 0) return; if (_t == 0 || _t > __t) _t = __t; }); if (t == 0 || t < _t) { t = _t; tlen = _len; } } best[len][k] = {height: t, length: tlen}; } } var edges = []; var triangles = []; var makesubtriangulation = function _makesubtriangulation(ai, bi, ci, depth) { var _i = [ai, bi, ci].sort(function(a,b){return a-b;}); if (data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index == -1) { triangles.push(new window.plugin.flyLinks.Triangle(locations[ai], locations[bi], locations[ci], depth)); } else { _makesubtriangulation(ai, bi, data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index, depth+1); _makesubtriangulation(bi, ci, data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index, depth+1); _makesubtriangulation(ci, ai, data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index, depth+1); edges.push(new window.plugin.flyLinks.Edge(locations[ai], locations[data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index], depth)); edges.push(new window.plugin.flyLinks.Edge(locations[bi], locations[data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index], depth)); edges.push(new window.plugin.flyLinks.Edge(locations[ci], locations[data[_i[0]][_i[1]-_i[0]][_i[2]-_i[1]].index], depth)); } } var maketriangulation = function _maketriangulation(len, a) { edges.push(new window.plugin.flyLinks.Edge(locations[index[a]], locations[index[a+len]], 0)); if (best[len][a].length == -1) return; makesubtriangulation(index[a], index[a+best[len][a].length], index[a+len], 1); _maketriangulation(best[len][a].length, a); _maketriangulation(len - best[len][a].length, a + best[len][a].length); } maketriangulation(index.length - 1, 0); return {edges: edges, triangles: triangles}; } var triangulation = triangulate(index, locations); var edges = triangulation.edges; var triangles = triangulation.triangles; $.each(edges, function(idx, edge) { drawLink(edge.a, edge.b, { color: '#FF0000', opacity: 1, weight: 1.5, clickable: false, smoothFactor: 10, dashArray: [6, 4], }); }); $.each(triangles, function(idx, triangle) { drawField(triangle.a, triangle.b, triangle.c, { stroke: false, fill: true, fillColor: '#FF0000', fillOpacity: 1 - Math.pow(0.85, triangle.depth), clickable: false, }); }); } window.plugin.flyLinks.Edge = function(a, b, depth) { this.a = a; this.b = b; this.depth = depth; } window.plugin.flyLinks.Triangle = function(a, b, c, depth) { this.a = a; this.b = b; this.c = c; this.depth = depth; } window.plugin.flyLinks.setup = function() { window.plugin.flyLinks.linksLayerGroup = new L.LayerGroup(); window.plugin.flyLinks.fieldsLayerGroup = new L.LayerGroup(); window.addHook('mapDataRefreshEnd', function(e) { window.plugin.flyLinks.updateLayer(); }); window.map.on('moveend', function() { window.plugin.flyLinks.updateLayer(); }); window.addLayerGroup('Fly links', window.plugin.flyLinks.linksLayerGroup, false); window.addLayerGroup('Fly fields', window.plugin.flyLinks.fieldsLayerGroup, false); } var setup = window.plugin.flyLinks.setup; // PLUGIN END ////////////////////////////////////////////////////////// setup.info = plugin_info; //add the script info data to the function as a property if(!window.bootPlugins) window.bootPlugins = []; window.bootPlugins.push(setup); // if IITC has already booted, immediately run the 'setup' function if(window.iitcLoaded && typeof setup === 'function') setup(); } // wrapper end // inject code into site context var script = document.createElement('script'); var info = {}; if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description }; script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');')); (document.body || document.head || document.documentElement).appendChild(script); -
asnapper created this gist
Feb 5, 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,106 @@ // ==UserScript== // @id disable-portal@asnapper // @name IITC plugin: Disable Portal // @category Tweaks // @version 0.0.1.20140205.104101 // @updateURL none // @downloadURL none // @description [local-2014-02-05-104101] Allows you disable specific portals for plugins like fly-links // @include https://www.ingress.com/intel* // @include http://www.ingress.com/intel* // @match https://www.ingress.com/intel* // @match http://www.ingress.com/intel* // @grant none // ==/UserScript== function wrapper(plugin_info) { // ensure plugin framework is there, even if iitc is not yet loaded if(typeof window.plugin !== 'function') window.plugin = function() {}; //PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!! //(leaving them in place might break the 'About IITC' page or break update checks) plugin_info.buildName = 'local'; plugin_info.dateTimeVersion = '20140205.104101'; plugin_info.pluginId = 'disable-portal'; //END PLUGIN AUTHORS NOTE // PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.disablePortal = function() {}; // array to hold all disabled portal GUIDs window.plugin.disablePortal.disabledGUID = []; window.plugin.disablePortal.disable = function(guid) { window.plugin.disablePortal.disabledGUID[guid] = true; window.plugin.disablePortal.addControl({guid:guid}); //if (window.plugin.flyLinks) // window.plugin.flyLinks.updateLayer(); window.runHooks('mapDataRefreshEnd'); }; window.plugin.disablePortal.enable = function(guid) { delete window.plugin.disablePortal.disabledGUID[guid]; window.plugin.disablePortal.addControl({guid:guid}); //if (window.plugin.flyLinks) // window.plugin.flyLinks.updateLayer(); window.runHooks('mapDataRefreshEnd'); }; window.plugin.disablePortal.addControl = function(data) { // delete html control var node = document.getElementById('disablePortal'); if (node) { node.parentNode.removeChild(node); } // build onClick attribute strings var onClickEnable = 'window.plugin.disablePortal.enable(\'' + data.guid+ '\')'; var onClickDisable = 'window.plugin.disablePortal.disable(\'' + data.guid+ '\')'; // (re-)create html control var element; if (data.guid in window.plugin.disablePortal.disabledGUID) { element = $('<div>').html( $('<a>').attr({onclick:onClickEnable, title:'Enable'}).text('Enable') ); } else { element = $('<div>').html( $('<a>').attr({onclick:onClickDisable, title:'Disable'}).text('Disable') ); } //element.attr({id:'disablePortal'}); // find location to insert // DEBUG: verify XPath query!! var htmlParent = document.evaluate('//*[@id="portaldetails"]/div[3]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; // insert (probably ugly...) if (htmlParent) htmlParent.innerHTML += '<aside id="disablePortal">' + element.html() + '</aside>'; }; window.plugin.disablePortal.updateControl = function(guid) { //var data.guid = guid; //window.plugin.disablePortal.addControl(data); }; window.addHook('portalDetailsUpdated', window.plugin.disablePortal.addControl); var setup = function() {}; // PLUGIN END ////////////////////////////////////////////////////////// setup.info = plugin_info; //add the script info data to the function as a property if(!window.bootPlugins) window.bootPlugins = []; window.bootPlugins.push(setup); // if IITC has already booted, immediately run the 'setup' function if(window.iitcLoaded && typeof setup === 'function') setup(); } // wrapper end // inject code into site context var script = document.createElement('script'); var info = {}; if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description }; script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');')); (document.body || document.head || document.documentElement).appendChild(script);