- /* global simplify */
- // ==UserScript==
- // @name WME Simplify Place Geometry
- // @description Simplifies geometry of area places in WME
- // @version 2018.05.07.02
- // @author SAR85
- // @copyright SAR85
- // @license CC BY-NC-ND
- // @grant none
- // @include https://www.waze.com/editor*
- // @include https://www.waze.com/*/editor*
- // @include https://beta.waze.com/*
- // @namespace https://greatest.deepsurf.us/en/scripts/367660-wme-simplify-place-geometry
- // @require https://greatest.deepsurf.us/scripts/24851-wazewrap/code/WazeWrap.js
- // ==/UserScript==
- /* global W */
- /* global OpenLayers */
-
- (function () {
- 'use strict';
- /* Global vars */
- var DEFAULT_SIMPLIFICATION_FACTOR = 5;
- var simplify;
- var simplifyVersion = '2018.05.07.01';
- var simplifyChanges = 'WME Simplify Area Geometry has been updated to version ' +
- simplifyVersion + '.\n' +
- '[*] Updated for editor compatibility.';
- var UpdateFeatureGeometry = require('Waze/Action/UpdateFeatureGeometry');
- var UpdateObject = require('Waze/Action/UpdateObject');
-
- function simpBootstrap() {
- if (W && W.loginManager && W.loginManager.events &&
- W.loginManager.events.register && $ && WazeWrap.Ready &&
- $('#map').size()) {
- simpInit();
- } else {
- window.setTimeout(function () {
- simpBootstrap();
- }, 1000);
- }
- }
-
- function initializeSimplifyFunc() {
- /*
- (c) 2013, Vladimir Agafonkin
- Simplify.js, a high-performance JS polyline simplification library
- mourner.github.io/simplify-js
- */
- function getSqDist(p1, p2) {
-
- var dx = p1.x - p2.x,
- dy = p1.y - p2.y;
-
- return dx * dx + dy * dy;
- }
- 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;
- }
- 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;
- }
- 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;
- }
- 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;
- }
- return simplify;
- }
-
- function simpInit() {
- /* HTML */
- var content = '<div id="simplifyarea"><p id="simplifyhelp" style="text-align: center; margin-bottom: 2px; text-decoration: underline; font-weight: bold; cursor: help;">WME Simplify Area Geometry</p><p style="text-align: center; margin: 0px;">Simplification factor: <input type="number" min="1" max="20" id="simpE" style="height: 20px; background-color: rgba(0,0,0,0.8); padding-left: 2px; border: 1px solid white; color: white; width: 50px"></p><p style="color: white;margin: 2px 0 0 0;"><a id="simplifylink" style="cursor:pointer; color: rgb(27,237,30)">Simplify Geometry</a> | <a id="clearlink" style="cursor:pointer; color: red;">Clear Geometry</a></p></div>';
- var css = {
- "display": "none",
- "position": "absolute",
- "top": "120px",
- "left": "73px",
- "padding": "4px",
- "background-color": "rgba(0,0,0,0.8)",
- "border-radius": "5px",
- "border": "none",
- "color": "white",
- "font-size": "0.9em"
- };
-
- /* Initialize simplification library */
- simplify = initializeSimplifyFunc();
-
- /* Add HTML to page and initialize*/
- $('#map').append(content);
- $('#simplifyarea').css(css);
- $('#simpE').val(localStorage.simplifyE ||
- DEFAULT_SIMPLIFICATION_FACTOR);
- $('#simplifylink').click(simplifyFeatureGeometry);
- $('#clearlink').click(clearFeatureGeometry);
- try {
- $('#simplifyarea').draggable();
- } catch (err) { }
-
- /* Event listeners */
- W.loginManager.events.register('afterloginchanged', null, simpInit);
- $('#simplifyhelp').click(function () {
- alert('To use WME Simplify Place Geometry: \n' +
- '1. Select an area place \n' +
- '2. Select an appropriate simplification factor (usually 5-10) \n' +
- '3. Click the link to simplify or clear the geometry');
- });
- $('#simpE').change(function () {
- localStorage.simplifyE = $('#simpE').val();
- });
- W.selectionManager.events.register('selectionchanged', null,
- function () {
- if (W.selectionManager.hasSelectedFeatures()) {
- var selectedItem = W.selectionManager.getSelectedFeatures()[0].model;
- if (!(selectedItem.geometry instanceof OpenLayers.Geometry.Polygon)) {
- return;
- }
- $('#simplifyarea').fadeIn('fast');
- } else {
- $('#simplifyarea').fadeOut('fast');
- }
- });
-
- /* Shortcut key = shift+j for simplifying */
- new WazeWrap.Interface.Shortcut('simplifyFeatureGeometry', 'editing', 'S+j', simplifyFeatureGeometry, this).add();
-
- /* Shortcut key = ctrl+shift+j for clearing */
- new WazeWrap.Interface.Shortcut('clearFeatureGeometry', 'editing', 'CS+j', clearFeatureGeometry, this).add();
-
- console.log('WME Simplify Area Geometry Initialized');
-
- /* Update Alert */
- if (typeof window.localStorage.simplifyVersion === 'undefined' || window.localStorage.simplifyVersion !== simplifyVersion) {
- alert(simplifyChanges);
- window.localStorage.simplifyVersion = simplifyVersion;
- }
- }
-
- function simplifyFeatureGeometry(e) {
- var place = W.selectionManager.getSelectedFeatures()[0];
- var oldGeometry = place.geometry.clone();
- var newGeometry = oldGeometry.clone();
-
- if (!W.selectionManager.hasSelectedFeatures() || W.selectionManager.getSelectedFeatures()[0].model.type !== 'venue' ||
- !W.selectionManager.getSelectedFeatures()[0].model.isGeometryEditable() ||
- !(W.selectionManager.getSelectedFeatures()[0].model.geometry instanceof OpenLayers.Geometry.Polygon)) {
- return;
- }
- e = $('#simpE').val() || DEFAULT_SIMPLIFICATION_FACTOR;
-
- newGeometry.components[0].components = simplify(oldGeometry.components[0].components, e, false);
- if (newGeometry.components[0].components.length <
- oldGeometry.components[0].components.length &&
- newGeometry.components[0].components.length > 2) {
- W.model.actionManager.add(new UpdateFeatureGeometry(
- 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,
- navAction;
- var venue = W.selectionManager.getSelectedFeatures()[0].model;
- var newEntryExitPoint = {
- entry: true,
- exit: true
- };
- var oldGeometry = venue.geometry;
-
- if (!W.selectionManager.hasSelectedFeatures() ||
- W.selectionManager.getSelectedFeatures()[0].model.type !== 'venue' ||
- !W.selectionManager.getSelectedFeatures()[0].model.isGeometryEditable() ||
- !(W.selectionManager.getSelectedFeatures()[0].model.geometry instanceof
- OpenLayers.Geometry.Polygon)) {
- return;
- }
-
- 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 UpdateFeatureGeometry(
- venue, W.model.venues, oldGeometry, newGeometry));
- navAction = new UpdateObject(venue, {
- entryExitPoints: [newEntryExitPoint]
- });
- navAction.eachGeometryField = function (e, t) {
- var i,
- n,
- s,
- r,
- o;
- for (r = e.entryExitPoints, o = [], n = 0, s = r.length;
- s > n; n++) {
- i = r[n], o.push(t.call(this, 'point', i.point, i));
- }
- return o;
- };
- W.model.actionManager.add(navAction);
- }
- }
- simpBootstrap();
- } ());