WME Simplify Place Geometry

Simplifies geometry of area places in WME

当前为 2015-02-26 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         WME Simplify Place Geometry
// @description  Simplifies geometry of area places in WME
// @version      0.9.1
// @author       SAR85
// @grant		 none
// @include      https://www.waze.com/editor/*
// @include      https://www.waze.com/*/editor/*
// @include      https://editor-beta.waze.com/*
// @namespace https://greasyfork.org/users/9321
// ==/UserScript==

/* Global vars */
var simplifyVersion = "0.9.1";
var simplifyChanges = "WME Simplify Area Geometry has been updated to version " + simplifyVersion + ". The shortcut has changed to 'shift+j' for simplifying geometry.  A feature has been added to clear geometry of areas.  The shortcut is 'ctrl+shift+j' to clear geometry.";
var simpUpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry");
var simpUpdateObject = require("Waze/Action/UpdateObject");
	
function simpBootstrap() {
	var bGreasemonkeyServiceDefined     = false;
	try
	{
		if ("object" === typeof Components.interfaces.gmIGreasemonkeyService)
		{
			bGreasemonkeyServiceDefined = true;
		}
	}
	catch (err)
	{
		// Ignore.
	}
	if ( "undefined" === typeof unsafeWindow  ||  ! bGreasemonkeyServiceDefined)
	{
		unsafeWindow    = ( function ()
		{
			var dummyElem   = document.createElement('p');
			dummyElem.setAttribute ('onclick', 'return window;');
			return dummyElem.onclick ();
		} ) ();
	}
	/* begin running the code! */
	window.setTimeout(simpInit, 2000);
	/*doesn't work in FF: $(document).ready(simpInit); */
}

function addSimplifyFunc() {
	/*
	 (c) 2013, Vladimir Agafonkin
	 Simplify.js, a high-performance JS polyline simplification library
	 mourner.github.io/simplify-js
	*/
	(function () { 'use strict';

		// to suit your point format, run search/replace for '.x' and '.y';
		// for 3D version, see 3d branch (configurability would draw significant performance overhead)

		// square distance between 2 points
		function getSqDist(p1, p2) {

			var dx = p1.x - p2.x,
				dy = p1.y - p2.y;

			return dx * dx + dy * dy;
		}

		// square distance from a point to a segment
		function getSqSegDist(p, p1, p2) {

			var x = p1.x,
				y = p1.y,
				dx = p2.x - x,
				dy = p2.y - y;

			if (dx !== 0 || dy !== 0) {

				var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);

				if (t > 1) {
					x = p2.x;
					y = p2.y;

				} else if (t > 0) {
					x += dx * t;
					y += dy * t;
				}
			}

			dx = p.x - x;
			dy = p.y - y;

			return dx * dx + dy * dy;
		}
		// rest of the code doesn't care about point format

		// basic distance-based simplification
		function simplifyRadialDist(points, sqTolerance) {

			var prevPoint = points[0],
				newPoints = [prevPoint],
				point;

			for (var i = 1, len = points.length; i < len; i++) {
				point = points[i];

				if (getSqDist(point, prevPoint) > sqTolerance) {
					newPoints.push(point);
					prevPoint = point;
				}
			}

			if (prevPoint !== point) newPoints.push(point);

			return newPoints;
		}

		// simplification using optimized Douglas-Peucker algorithm with recursion elimination
		function simplifyDouglasPeucker(points, sqTolerance) {

			var len = points.length,
				MarkerArray = typeof Uint8Array !== 'undefined' ? Uint8Array : Array,
				markers = new MarkerArray(len),
				first = 0,
				last = len - 1,
				stack = [],
				newPoints = [],
				i, maxSqDist, sqDist, index;

			markers[first] = markers[last] = 1;

			while (last) {

				maxSqDist = 0;

				for (i = first + 1; i < last; i++) {
					sqDist = getSqSegDist(points[i], points[first], points[last]);

					if (sqDist > maxSqDist) {
						index = i;
						maxSqDist = sqDist;
					}
				}

				if (maxSqDist > sqTolerance) {
					markers[index] = 1;
					stack.push(first, index, index, last);
				}

				last = stack.pop();
				first = stack.pop();
			}

			for (i = 0; i < len; i++) {
				if (markers[i]) newPoints.push(points[i]);
			}

			return newPoints;
		}

		// both algorithms combined for awesome performance
		function simplify(points, tolerance, highestQuality) {

			if (points.length <= 1) return points;

			var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;

			points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
			points = simplifyDouglasPeucker(points, sqTolerance);

			return points;
		}

		// export as AMD module / Node module / browser or worker variable
		if (typeof define === 'function' && define.amd) define(function() { return simplify; });
		else if (typeof module !== 'undefined') module.exports = simplify;
		else if (typeof self !== 'undefined') self.simplify = simplify;
		else window.simplify = simplify;

	})();
}

function simpInit() {
	/* HTML */
 	var tab = '<li><a href="#sidepanel-simplifyarea" data-toggle="tab" id="simplifytab">Simplify Area</a></li>';
	var content = '<div class="tab-pane" id="sidepanel-simplifyarea"><h1 style="display: block; position:relative; margin-top: -10px; margin-bottom: 10px">Simplify Area Place Geometry</h1><hr><p>Simplification factor:</p><p>0<input type="range" id="simpE" step="1" min="1" max="100" defaultValue="50"></input>100</p><p>Press "shift+j" to simplify or "ctrl-shift-j" to clear the geometry of a selected area place.</p></div>';
	/* Initialize simplification library */
	addSimplifyFunc();
	/* Add HTML to page */
	$('h2 + ul.nav-tabs').append(tab);
	$('h2 + ul.nav-tabs + .tab-content').append(content);
	/* Add functions to page */
	self.simplifyFeatureGeometry = simplifyFeatureGeometry;
	self.clearFeatureGeometry = clearFeatureGeometry;
	/* Shortcut key = shift+j for simplifying */
	W.accelerators.addAction('simplifyFeatureGeometry', {group: "editing"});
	W.accelerators.events.register('simplifyFeatureGeometry',null,function(){simplifyFeatureGeometry()});
	W.accelerators.registerShortcuts({'S+j': "simplifyFeatureGeometry"});
	/* Shortcut key = ctrl-shift-j for clearing */
	W.accelerators.addAction('clearFeatureGeometry', {group: "editing"});
	W.accelerators.events.register('clearFeatureGeometry',null,function(){clearFeatureGeometry()});
	W.accelerators.registerShortcuts({'CS+j': "clearFeatureGeometry"});
	console.log("WME Simplify Area Geometry Initialized");
	/* Update Alert */
	if (window.localStorage.simplifyVersion == 'undefined' || window.localStorage.simplifyVersion !== simplifyVersion) {
		alert(simplifyChanges);
		window.localStorage.simplifyVersion = simplifyVersion;
	}
}

function simplifyFeatureGeometry(e) {
    if (!W.selectionManager.hasSelectedItems() || W.selectionManager.selectedItems[0].model.type !== "venue" || !W.selectionManager.selectedItems[0].model.isGeometryEditable() || !W.selectionManager.selectedItems[0].model.geometry instanceof OpenLayers.Geometry.Polygon) return;
	e = e || $('#simpE').val();
    var place = W.selectionManager.selectedItems[0];
    var oldGeometry = place.geometry.clone();
    var newGeometry = oldGeometry.clone();
    newGeometry.components[0].components = simplify(oldGeometry.components[0].components, e, false);
    if (newGeometry.components[0].components.length < oldGeometry.components[0].components.length) {
		W.model.actionManager.add(new simpUpdateFeatureGeometry(place.model,W.model.venues,oldGeometry,newGeometry));
		console.log("WME Simplify Area Geometry: " + place.model.attributes.name + " simplified from " + oldGeometry.components[0].components.length + " to " + newGeometry.components[0].components.length + " geo nodes using factor " + e + ".");
	} else {
		console.log("Geo nodes cannot be simplified from " + oldGeometry.components[0].components.length + " to " + newGeometry.components[0].components.length + ".");
	}
}

function clearFeatureGeometry() {
    var newGeometry;
    var venue = W.selectionManager.selectedItems[0].model;
    var newEntryExitPoint = {entry: true, exit: true};
    var oldGeometry = venue.geometry;

    if (oldGeometry.components[0].components.length > 4) {
        newGeometry = oldGeometry.getBounds().toGeometry();
        if (newGeometry.getArea() > 160) newGeometry.resize(0.5,newGeometry.getCentroid());
        newEntryExitPoint.point = newGeometry.getCentroid();
        W.model.actionManager.add(new simpUpdateFeatureGeometry(venue,W.model.venues,oldGeometry,newGeometry));
        W.model.actionManager.add(new simpUpdateObject(venue,{entryExitPoints: [newEntryExitPoint]}));
    }
}

simpBootstrap();