您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Clone, Orthogonalize (mini version from MagicPlaces)
// ==UserScript== // @name WME MagicPlaces // @description Clone, Orthogonalize (mini version from MagicPlaces) // @include https://www.waze.com/editor/* // @include https://www.waze.com/*/editor/* // @include https://beta.waze.com/* // @version 1.1.1 // @grant none // @license CC BY 4.0 // @namespace https://gf.qytechs.cn/users/68507 // ==/UserScript== function run_magicwand() { var wmelmw_version = "1.1.0"; /* bootstrap, will call initialiseHighlights() */ function bootstraMagicPlaces() { var bGreasemonkeyServiceDefined = false; /* begin running the code! */ setTimeout(initialiseMagicPlaces, 500); } /* helper function */ function getElClass(classname, node) { if (!node) node = document.getElementsByTagName("body")[0]; var a = []; var re = new RegExp('\\b' + classname + '\\b'); var els = node.getElementsByTagName("*"); for (var i = 0, j = els.length; i < j; i++) if (re.test(els[i].className)) a.push(els[i]); return a; } function getElId(node) { return document.getElementById(node); } /* =========================================================================== */ function initialiseMagicPlaces() { try { if (!((typeof window.Waze.map != undefined) && (undefined != typeof window.Waze.map.events.register) && (undefined != typeof window.Waze.selectionManager.events.register ) && (undefined != typeof window.Waze.loginManager.events.register) )) { setTimeout(initialiseMagicPlaces, 1000); return; } } catch (err) { setTimeout(initialiseMagicPlaces, 1000); return; } var userInfo = getElId('user-info'); var userTabs = getElId('user-tabs'); if(!getElClass('nav-tabs', userTabs)[0]) { setTimeout(initialiseMagicPlaces, 1000); return; } var navTabs = getElClass('nav-tabs', userTabs)[0]; var tabContent = getElClass('tab-content', userInfo)[0]; var newtab = document.createElement('li'); newtab.innerHTML = '<a href="#sidepanel-magicwand" data-toggle="tab">MagicPlaces</a>'; navTabs.appendChild(newtab); // add new box to left of the map var addon = document.createElement('section'); addon.innerHTML = '<b>WME Magic Wand</b> v' + wmelmw_version + '<br>' + '<label>Максимальный угол <input type="text" id="_cMagicPlacesAngleThreshold" name="_cMagicPlacesAngleThreshold" value="12" size="3" maxlength="2" /></label><br/>' + 'Значение, на которое скрипт может исправить угол, если для выпремления тербуется больше - не меняет (по умолчанию 12)<br><br>' + '<label>Степень выпрямления <input type="text" id="_cMagicPlacesSimplification" name="_cMagicPlacesSimplification" value="3" size="5" maxlength="4" /></label><br/><br/>' + 'Значение угла со значение котрого имли меньше, убираются узлы рекомендовано от 0 до 5 (по умолчанию 4)<br><br>'; addon.id = "sidepanel-magicwand"; addon.className = "tab-pane"; tabContent.appendChild(addon); loadWMEMagicPlacesSettings(); // Event listeners Waze.selectionManager.events.register("selectionchanged", null, insertLandmarkSelectedButtons); window.addEventListener("beforeunload", saveWMEMagicPlacesOptions, false); // Hotkeys registerKeyShortcut("WMEMagicPlaces_CloneLandmark", "Clone Landmark", cloneLandmark, {"C+c": "WMEMagicPlaces_CloneLandmark"}); registerKeyShortcut("WMEMagicPlaces_OrthogonalizeLandmark", "Orthogonalize Landmark", Orthogonalize, {"C+x": "WMEMagicPlaces_OrthogonalizeLandmark"}); registerKeyShortcut("WMEMagicPlaces_SimplifyLandmark", "Simplify Landmark", simplifySelectedLandmark, {"C+j": "WMEMagicPlaces_SimplifyLandmark"}); } function registerKeyShortcut(action_name, annotation, callback, key_map) { Waze.accelerators.addAction(action_name, {group: 'default'}); Waze.accelerators.events.register(action_name, null, callback); Waze.accelerators._registerShortcuts(key_map); } function loadWMEMagicPlacesSettings () { if (localStorage.WMEMagicPlacesScript) { console.log("WME MagicPlaces: loading options"); var options = JSON.parse(localStorage.WMEMagicPlacesScript); getElId('_cMagicPlacesAngleThreshold').value = typeof options[0] != 'undefined' ? options[0] : 12; getElId('_cMagicPlacesSimplification').value = typeof options[1] != 'undefined' ? options[1] : 4; } } function saveWMEMagicPlacesOptions() { if (localStorage) { console.log("WME MagicPlaces: saving options"); var options = []; // preserve previous options which may get lost after logout if (localStorage.WMEMagicPlacesScript) options = JSON.parse(localStorage.WMEMagicPlacesScript); options[0] = getElId('_cMagicPlacesAngleThreshold').value; options[1] = getElId('_cMagicPlacesSimplification').value; localStorage.WMEMagicPlacesScript = JSON.stringify(options); } } var insertLandmarkSelectedButtons = function(e) { if(Waze.selectionManager.selectedItems.length == 0 || Waze.selectionManager.selectedItems[0].model.type != 'venue') return; if(getElId('_bMagicPlacesEdit_CloneLandmark') != null) return; $('#landmark-edit-general').prepend( '<div class="form-group"> \ <div class="controls"> \ <input style="padding: 6px 8px;" type="button" id="_bMagicPlacesEdit_CloneLandmark" name="_bMagicPlacesEdit_CloneLandmark" class="btn btn-default" value="Клонировать" title="Ctrl+C (default)" /> \ <input style="padding: 6px 8px;" type="button" id="_bMagicPlacesEdit_Corners" name="_bMagicPlacesEdit_Corners" class="btn btn-default" value="Выровнять" title="Ctrl+X (default)"/>\ <input style="padding: 6px 8px;" type="button" id="_bMagicPlacesEdit_Simplify" name="_bMagicPlacesEdit_Simplify" class="btn btn-default" value="Упростить" title="Ctrl+J (default)"/>\ </div> \ </div>' ); $('#_bMagicPlacesEdit_CloneLandmark').click(cloneLandmark); $('#_bMagicPlacesEdit_Corners').click(Orthogonalize); $('#_bMagicPlacesEdit_Simplify').click(simplifySelectedLandmark); }; var simplifySelectedLandmark = function () { var selectorManager = Waze.selectionManager; if (!selectorManager.hasSelectedItems() || selectorManager.selectedItems[0].model.type !== "venue" || !selectorManager.selectedItems[0].model.isGeometryEditable()) { return; } var simplifyFactor = $('#_cMagicPlacesSimplification').val(); var SelectedLandmark = selectorManager.selectedItems[0]; var oldGeometry = SelectedLandmark.geometry.clone(); var LineString = new OpenLayers.Geometry.LineString(oldGeometry.components[0].components); LineString = LineString.simplify(simplifyFactor); var newGeometry = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(LineString.components)); if (newGeometry.components[0].components.length < oldGeometry.components[0].components.length) { var UpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry"); W.model.actionManager.add(new UpdateFeatureGeometry(SelectedLandmark.model, W.model.venues, oldGeometry, newGeometry)); } }; var cloneLandmark = function () { var selectorManager = Waze.selectionManager; if (!selectorManager.hasSelectedItems() || selectorManager.selectedItems[0].model.type != 'venue') { return; } var SelectedLandmark = selectorManager.selectedItems[0]; var ClonedLandmark = SelectedLandmark.clone(); ClonedLandmark.geometry.move(50, 50); // move to some offset ClonedLandmark.geometry.clearBounds(); var wazefeatureVectorLandmark = require("Waze/Feature/Vector/Landmark"); var wazeActionAddLandmark = require("Waze/Action/AddLandmark"); var NewLandmark = new wazefeatureVectorLandmark(); NewLandmark.geometry = ClonedLandmark.geometry; NewLandmark.attributes.categories = SelectedLandmark.model.attributes.categories; Waze.model.actionManager.add(new wazeActionAddLandmark(NewLandmark)); selectorManager.select([NewLandmark]); }; var Orthogonalize = function() { if (Waze.selectionManager.selectedItems.length <= 0 || Waze.selectionManager.selectedItems[0].model.type != 'venue') { return; } var SelectedLandmark = Waze.selectionManager.selectedItems[0]; var geom = SelectedLandmark.geometry.clone(); var components = geom.components[0].components; var functor = new OrthogonalizeId(components); var newWay = functor.action(); var wazeActionUpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry"); var removeVertices = []; var undoGeometry = SelectedLandmark.geometry.clone(); for (var i = 0; i < newWay.length; i++) { if (newWay[i] === false) { removeVertices.push(SelectedLandmark.geometry.components[0].components[i]); } else { SelectedLandmark.geometry.components[0].components[i].x = newWay[i].x; SelectedLandmark.geometry.components[0].components[i].y = newWay[i].y; } } if (removeVertices) { SelectedLandmark.geometry.components[0].removeComponents(removeVertices); } SelectedLandmark.geometry.components[0].clearBounds(); var action = new wazeActionUpdateFeatureGeometry(SelectedLandmark.model, Waze.model.venues, undoGeometry, SelectedLandmark.geometry); Waze.model.actionManager.add(action); delete undoGeometry; }; var OrthogonalizeId = function (way) { var threshold = getElId('_cMagicPlacesAngleThreshold').value, // degrees within right or straight to alter lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180), upperThreshold = Math.cos(threshold * Math.PI / 180); this.way = way; this.action = function () { var nodes = this.way, points = nodes.slice(0, nodes.length - 1).map(function (n) { var t = n.clone(); var p = t.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326")); p.y = lat2latp(p.y); return p; }), corner = {i: 0, dotp: 1}, epsilon = 1e-4, i, j, score, motions; // Triangle if (nodes.length === 4) { for (i = 0; i < 1000; i++) { motions = points.map(calcMotion); var tmp = addPoints(points[corner.i], motions[corner.i]); points[corner.i].x = tmp.x; points[corner.i].y = tmp.y; score = corner.dotp; if (score < epsilon) { break; } } var n = points[corner.i]; n.y = latp2lat(n.y); var pp = n.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); var id = nodes[corner.i].id; for (i = 0; i < nodes.length; i++) { if (nodes[i].id != id) { continue; } nodes[i].x = pp.x; nodes[i].y = pp.y; } return nodes; } else { var best, originalPoints = nodes.slice(0, nodes.length - 1).map(function (n) { var t = n.clone(); var p = t.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326")); p.y = lat2latp(p.y); return p; }); score = Infinity; for (i = 0; i < 1000; i++) { motions = points.map(calcMotion); for (j = 0; j < motions.length; j++) { var tmp = addPoints(points[j], motions[j]); points[j].x = tmp.x; points[j].y = tmp.y; } var newScore = squareness(points); if (newScore < score) { best = points.clone(); score = newScore; } if (score < epsilon) { break; } } points = best; for (i = 0; i < points.length; i++) { // only move the points that actually moved if (originalPoints[i].x !== points[i].x || originalPoints[i].y !== points[i].y) { var n = points[i]; n.y = latp2lat(n.y); var pp = n.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); var id = nodes[i].id; for (j = 0; j < nodes.length; j++) { if (nodes[j].id != id) { continue; } nodes[j].x = pp.x; nodes[j].y = pp.y; } } } // remove empty nodes on straight sections for (i = 0; i < points.length; i++) { var dotp = normalizedDotProduct(i, points); if (dotp < -1 + epsilon) { id = nodes[i].id; for (j = 0; j < nodes.length; j++) { if (nodes[j].id != id) { continue; } nodes[j] = false; } } } return nodes; } function calcMotion(b, i, array) { var a = array[(i - 1 + array.length) % array.length], c = array[(i + 1) % array.length], p = subtractPoints(a, b), q = subtractPoints(c, b), scale, dotp; scale = 2 * Math.min(euclideanDistance(p, {x: 0, y: 0}), euclideanDistance(q, {x: 0, y: 0})); p = normalizePoint(p, 1.0); q = normalizePoint(q, 1.0); dotp = filterDotProduct(p.x * q.x + p.y * q.y); // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270). if (array.length > 3) { if (dotp < -0.707106781186547) { dotp += 1.0; } } else if (dotp && Math.abs(dotp) < corner.dotp) { corner.i = i; corner.dotp = Math.abs(dotp); } return normalizePoint(addPoints(p, q), 0.1 * dotp * scale); } }; function squareness(points) { return points.reduce(function (sum, val, i, array) { var dotp = normalizedDotProduct(i, array); dotp = filterDotProduct(dotp); return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1))); }, 0); } function normalizedDotProduct(i, points) { var a = points[(i - 1 + points.length) % points.length], b = points[i], c = points[(i + 1) % points.length], p = subtractPoints(a, b), q = subtractPoints(c, b); p = normalizePoint(p, 1.0); q = normalizePoint(q, 1.0); return p.x * q.x + p.y * q.y; } function subtractPoints(a, b) { return {x: a.x - b.x, y: a.y - b.y}; } function addPoints(a, b) { return {x: a.x + b.x, y: a.y + b.y}; } function euclideanDistance(a, b) { var x = a.x - b.x, y = a.y - b.y; return Math.sqrt((x * x) + (y * y)); } function normalizePoint(point, scale) { var vector = {x: 0, y: 0}; var length = Math.sqrt(point.x * point.x + point.y * point.y); if (length !== 0) { vector.x = point.x / length; vector.y = point.y / length; } vector.x *= scale; vector.y *= scale; return vector; } function filterDotProduct(dotp) { if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) { return dotp; } return 0; } this.isDisabled = function (nodes) { var points = nodes.slice(0, nodes.length - 1).map(function (n) { var p = n.toLonLat().transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326")); return {x: p.lat, y: p.lon}; }); return squareness(points); }; }; function lat2latp(lat) { return 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * (Math.PI / 180) / 2)); } function latp2lat(a) { return 180 / Math.PI * (2 * Math.atan(Math.exp(a * Math.PI / 180)) - Math.PI / 2); } // Point class function Point(x, y) { this.x = x; this.y = y; this.toString = function () { return "x: " + x + ", y: " + y; }; this.rotateRight = function (p1, p2) { // cross product, + is counterclockwise, - is clockwise return ((p2.x * y - p2.y * x) - (p1.x * y - p1.y * x) + (p1.x * p2.y - p1.y * p2.x)) < 0; }; } Point.prototype.add = function(v){ return new Point(this.x + v.x, this.y + v.y); }; Point.prototype.clone = function(){ return new Point(this.x, this.y); }; Point.prototype.degreesTo = function(v){ var dx = this.x - v.x; var dy = this.y - v.y; var angle = Math.atan2(dy, dx); // radians return angle * (180 / Math.PI); // degrees }; Point.prototype.distance = function(v){ var x = this.x - v.x; var y = this.y - v.y; return Math.sqrt(x * x + y * y); }; Point.prototype.equals = function(toCompare){ return this.x == toCompare.x && this.y == toCompare.y; }; Point.prototype.interpolate = function(v, f){ return new Point((this.x + v.x) * f, (this.y + v.y) * f); }; Point.prototype.length = function(){ return Math.sqrt(this.x * this.x + this.y * this.y); }; Point.prototype.normalize = function(thickness){ var l = this.length(); this.x = this.x / l * thickness; this.y = this.y / l * thickness; }; Point.prototype.orbit = function(origin, arcWidth, arcHeight, degrees){ var radians = degrees * (Math.PI / 180); this.x = origin.x + arcWidth * Math.cos(radians); this.y = origin.y + arcHeight * Math.sin(radians); }; Point.prototype.offset = function(dx, dy){ this.x += dx; this.y += dy; }; Point.prototype.subtract = function(v){ return new Point(this.x - v.x, this.y - v.y); }; Point.prototype.toString = function(){ return "(x=" + this.x + ", y=" + this.y + ")"; }; Point.interpolate = function(pt1, pt2, f){ return new Point((pt1.x + pt2.x) * f, (pt1.y + pt2.y) * f); }; Point.polar = function(len, angle){ return new Point(len * Math.cos(angle), len * Math.sin(angle)); }; Point.distance = function(pt1, pt2){ var x = pt1.x - pt2.x; var y = pt1.y - pt2.y; return Math.sqrt(x * x + y * y); }; /* engage! =================================================================== */ bootstraMagicPlaces(); } /* end ======================================================================= */ var DLscript = document.createElement("script"); DLscript.textContent = run_magicwand.toString() + ' \n' + 'run_magicwand();'; DLscript.setAttribute("type", "application/javascript"); document.body.appendChild(DLscript);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址