From bdefb90d23c1605282def22339db7c6de6d56454 Mon Sep 17 00:00:00 2001 From: Mark Friedrich Date: Sun, 24 Dec 2017 01:09:29 +0100 Subject: [PATCH] - added a 2D collision detection for new added systems, closed #570 --- js/app/map/layout.js | 95 ++++++++++++++++++++++++------ js/app/map/map.js | 21 ++++++- js/app/map/system.js | 4 +- public/js/v1.3.2/app/map/layout.js | 95 ++++++++++++++++++++++++------ public/js/v1.3.2/app/map/map.js | 21 ++++++- public/js/v1.3.2/app/map/system.js | 4 +- 6 files changed, 198 insertions(+), 42 deletions(-) diff --git a/js/app/map/layout.js b/js/app/map/layout.js index 873f143e..d0b7a4c9 100644 --- a/js/app/map/layout.js +++ b/js/app/map/layout.js @@ -40,18 +40,48 @@ define(() => { */ this._getElementDimension = (element) => { let dim = null; - if(element){ - // add "gap" to a and b in order to have some space around elements - dim = { - left: element.style.left ? parseInt(element.style.left, 10) : 0, - top: element.style.top ? parseInt(element.style.top, 10) : 0, - a: parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX, - b: parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY, - width: element.offsetWidth, - height: element.offsetHeight - }; + + let left = 0; + let top = 0; + let a = 0; + let b = 0; + let width = this._config.newElementWidth; + let height = this._config.newElementHeight; + + if(Array.isArray(element)){ + // xy coordinates + let point = [ + element[0] ? parseInt(element[0], 10) : 0, + element[1] ? parseInt(element[1], 10) : 0 + ]; + + if(this._config.grid){ + point = this._transformPointToGrid(point); + } + + left = point[0]; + top = point[1]; + a = this._config.gapX ; + b = this._config.gapY ; + }else if(element){ + // DOM element + left = element.style.left ? parseInt(element.style.left, 10) : 0; + top = element.style.top ? parseInt(element.style.top, 10) : 0; + a = parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX; + b = parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY; + width = element.offsetWidth; + height = element.offsetHeight; } - return dim; + + // add "gap" to a and b in order to have some space around elements + return { + left: left, + top: top, + a: a, + b: b, + width: width, + height: height + }; }; /** @@ -96,6 +126,18 @@ define(() => { return dimensions; }; + /** + * transform a x/y point into a x/y point that snaps to grid + * @param point + * @returns {*} + * @private + */ + this._transformPointToGrid = (point) => { + point[0] = Math.floor(point[0] / this._config.grid[0]) * this._config.grid[0]; + point[1] = Math.floor(point[1] / this._config.grid[1]) * this._config.grid[1]; + return point; + }; + /** * Transform a x/y coordinate into a 2D element with width/height * @param centerDimension @@ -136,8 +178,9 @@ define(() => { // transform to grid coordinates (if grid snapping is enabled) ------------------------------------ if(this._config.grid){ - left = Math.floor(left / this._config.grid[0]) * this._config.grid[0]; - top = Math.floor(top / this._config.grid[1]) * this._config.grid[1]; + let point = this._transformPointToGrid([left, top]); + left = point[0]; + top = point[1]; } dim = { @@ -239,14 +282,30 @@ define(() => { steps = steps || 1; loops = loops || 1; + if(loops === 1){ + // check center element + let centerDimension = this._getElementDimension(this._config.center); + if (!this._isOverlapping(centerDimension, dimensionContainer, allDimensions)) { + dimensions.push({ + left: centerDimension.left, + top: centerDimension.top, + width: centerDimension.width, + height: centerDimension.height + }); + // render debug element + this._showDebugElement(centerDimension, 0); + + maxResults--; + } + } + // increase the "gab" between center element and potential found dimensions... // ... for each recursive loop call, to get an elliptical cycle beyond - // -> defaultGab for 1. loop, ..., defaultGab + 3 * defaultGab/ 2 for 3. loop - this._config.gapX = this._config.defaultGapX + loops * Math.round(this._config.defaultGapX / 2); - this._config.gapY = this._config.defaultGapY + loops * Math.round(this._config.defaultGapY / 2); + this._config.gapX = this._config.defaultGapX + (loops - 1) * 20; + this._config.gapY = this._config.defaultGapY + (loops - 1) * 20; let centerDimension = this._getElementDimension(this._config.center); - do { + while(maxResults > 0 && start < end){ // get all potential coordinates on an eclipse around a given "centerElementDimension" let coordinate = this._getEllipseCoordinates(centerDimension, end); // transform relative x/y coordinate into a absolute 2D area @@ -264,7 +323,7 @@ define(() => { maxResults--; } end -= angle; - } while (maxResults > 0 && start < end); + } if(maxResults > 0 && loops < this._config.loops){ loops++; diff --git a/js/app/map/map.js b/js/app/map/map.js index fbf4e06a..b2117d81 100644 --- a/js/app/map/map.js +++ b/js/app/map/map.js @@ -10,6 +10,7 @@ define([ 'bootbox', 'app/map/util', 'app/map/system', + 'app/map/layout', 'app/map/magnetizing', 'app/map/scrollbar', 'dragToSelect', @@ -17,7 +18,7 @@ define([ 'app/map/contextmenu', 'app/map/overlay', 'app/map/local' -], function($, Init, Util, Render, bootbox, MapUtil, System, MagnetizerWrapper) { +], function($, Init, Util, Render, bootbox, MapUtil, System, Layout, MagnetizerWrapper) { 'use strict'; @@ -2661,6 +2662,24 @@ define([ switch(action){ case 'add_system': // add new system dialog + let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension]; + let positionFinder = new Layout.Position({ + container: currentMapElement[0], + center: [position.x, position.y], + loops: 5, + defaultGapX: 10, + defaultGapY: 10, + grid: currentMapElement.hasClass(MapUtil.config.mapGridClass) ? grid : false, + debug: false + }); + + let dimensions = positionFinder.findNonOverlappingDimensions(1, 8); + + if(dimensions.length){ + position.x = dimensions[0].left; + position.y = dimensions[0].top; + } + showNewSystemDialog(currentMap, {position: position}); break; case 'select_all': diff --git a/js/app/map/system.js b/js/app/map/system.js index 3abef9ee..52da853b 100644 --- a/js/app/map/system.js +++ b/js/app/map/system.js @@ -309,7 +309,7 @@ define([ let x = 0; let y = 0; - let position = new Layout.Position({ + let positionFinder = new Layout.Position({ container: mapContainer[0], center: sourceSystem[0], loops: 4, @@ -317,7 +317,7 @@ define([ debug: false }); - let dimensions = position.findNonOverlappingDimensions(1, 16); + let dimensions = positionFinder.findNonOverlappingDimensions(1, 16); if(dimensions.length){ //... empty map space found x = dimensions[0].left; diff --git a/public/js/v1.3.2/app/map/layout.js b/public/js/v1.3.2/app/map/layout.js index 873f143e..d0b7a4c9 100644 --- a/public/js/v1.3.2/app/map/layout.js +++ b/public/js/v1.3.2/app/map/layout.js @@ -40,18 +40,48 @@ define(() => { */ this._getElementDimension = (element) => { let dim = null; - if(element){ - // add "gap" to a and b in order to have some space around elements - dim = { - left: element.style.left ? parseInt(element.style.left, 10) : 0, - top: element.style.top ? parseInt(element.style.top, 10) : 0, - a: parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX, - b: parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY, - width: element.offsetWidth, - height: element.offsetHeight - }; + + let left = 0; + let top = 0; + let a = 0; + let b = 0; + let width = this._config.newElementWidth; + let height = this._config.newElementHeight; + + if(Array.isArray(element)){ + // xy coordinates + let point = [ + element[0] ? parseInt(element[0], 10) : 0, + element[1] ? parseInt(element[1], 10) : 0 + ]; + + if(this._config.grid){ + point = this._transformPointToGrid(point); + } + + left = point[0]; + top = point[1]; + a = this._config.gapX ; + b = this._config.gapY ; + }else if(element){ + // DOM element + left = element.style.left ? parseInt(element.style.left, 10) : 0; + top = element.style.top ? parseInt(element.style.top, 10) : 0; + a = parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX; + b = parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY; + width = element.offsetWidth; + height = element.offsetHeight; } - return dim; + + // add "gap" to a and b in order to have some space around elements + return { + left: left, + top: top, + a: a, + b: b, + width: width, + height: height + }; }; /** @@ -96,6 +126,18 @@ define(() => { return dimensions; }; + /** + * transform a x/y point into a x/y point that snaps to grid + * @param point + * @returns {*} + * @private + */ + this._transformPointToGrid = (point) => { + point[0] = Math.floor(point[0] / this._config.grid[0]) * this._config.grid[0]; + point[1] = Math.floor(point[1] / this._config.grid[1]) * this._config.grid[1]; + return point; + }; + /** * Transform a x/y coordinate into a 2D element with width/height * @param centerDimension @@ -136,8 +178,9 @@ define(() => { // transform to grid coordinates (if grid snapping is enabled) ------------------------------------ if(this._config.grid){ - left = Math.floor(left / this._config.grid[0]) * this._config.grid[0]; - top = Math.floor(top / this._config.grid[1]) * this._config.grid[1]; + let point = this._transformPointToGrid([left, top]); + left = point[0]; + top = point[1]; } dim = { @@ -239,14 +282,30 @@ define(() => { steps = steps || 1; loops = loops || 1; + if(loops === 1){ + // check center element + let centerDimension = this._getElementDimension(this._config.center); + if (!this._isOverlapping(centerDimension, dimensionContainer, allDimensions)) { + dimensions.push({ + left: centerDimension.left, + top: centerDimension.top, + width: centerDimension.width, + height: centerDimension.height + }); + // render debug element + this._showDebugElement(centerDimension, 0); + + maxResults--; + } + } + // increase the "gab" between center element and potential found dimensions... // ... for each recursive loop call, to get an elliptical cycle beyond - // -> defaultGab for 1. loop, ..., defaultGab + 3 * defaultGab/ 2 for 3. loop - this._config.gapX = this._config.defaultGapX + loops * Math.round(this._config.defaultGapX / 2); - this._config.gapY = this._config.defaultGapY + loops * Math.round(this._config.defaultGapY / 2); + this._config.gapX = this._config.defaultGapX + (loops - 1) * 20; + this._config.gapY = this._config.defaultGapY + (loops - 1) * 20; let centerDimension = this._getElementDimension(this._config.center); - do { + while(maxResults > 0 && start < end){ // get all potential coordinates on an eclipse around a given "centerElementDimension" let coordinate = this._getEllipseCoordinates(centerDimension, end); // transform relative x/y coordinate into a absolute 2D area @@ -264,7 +323,7 @@ define(() => { maxResults--; } end -= angle; - } while (maxResults > 0 && start < end); + } if(maxResults > 0 && loops < this._config.loops){ loops++; diff --git a/public/js/v1.3.2/app/map/map.js b/public/js/v1.3.2/app/map/map.js index fbf4e06a..b2117d81 100644 --- a/public/js/v1.3.2/app/map/map.js +++ b/public/js/v1.3.2/app/map/map.js @@ -10,6 +10,7 @@ define([ 'bootbox', 'app/map/util', 'app/map/system', + 'app/map/layout', 'app/map/magnetizing', 'app/map/scrollbar', 'dragToSelect', @@ -17,7 +18,7 @@ define([ 'app/map/contextmenu', 'app/map/overlay', 'app/map/local' -], function($, Init, Util, Render, bootbox, MapUtil, System, MagnetizerWrapper) { +], function($, Init, Util, Render, bootbox, MapUtil, System, Layout, MagnetizerWrapper) { 'use strict'; @@ -2661,6 +2662,24 @@ define([ switch(action){ case 'add_system': // add new system dialog + let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension]; + let positionFinder = new Layout.Position({ + container: currentMapElement[0], + center: [position.x, position.y], + loops: 5, + defaultGapX: 10, + defaultGapY: 10, + grid: currentMapElement.hasClass(MapUtil.config.mapGridClass) ? grid : false, + debug: false + }); + + let dimensions = positionFinder.findNonOverlappingDimensions(1, 8); + + if(dimensions.length){ + position.x = dimensions[0].left; + position.y = dimensions[0].top; + } + showNewSystemDialog(currentMap, {position: position}); break; case 'select_all': diff --git a/public/js/v1.3.2/app/map/system.js b/public/js/v1.3.2/app/map/system.js index 3abef9ee..52da853b 100644 --- a/public/js/v1.3.2/app/map/system.js +++ b/public/js/v1.3.2/app/map/system.js @@ -309,7 +309,7 @@ define([ let x = 0; let y = 0; - let position = new Layout.Position({ + let positionFinder = new Layout.Position({ container: mapContainer[0], center: sourceSystem[0], loops: 4, @@ -317,7 +317,7 @@ define([ debug: false }); - let dimensions = position.findNonOverlappingDimensions(1, 16); + let dimensions = positionFinder.findNonOverlappingDimensions(1, 16); if(dimensions.length){ //... empty map space found x = dimensions[0].left;