diff --git a/src/module_vmap/module/javascript/app/vmap/tools/select/select.js b/src/module_vmap/module/javascript/app/vmap/tools/select/select.js index 6a7eddf0e1b15822a8732b90e569e4e05093d0fd..64f0ec6defefc3aaa54c1d48e60eaac4c4036bd8 100755 --- a/src/module_vmap/module/javascript/app/vmap/tools/select/select.js +++ b/src/module_vmap/module/javascript/app/vmap/tools/select/select.js @@ -366,6 +366,7 @@ nsVmap.nsToolsManager.Select.prototype.selectController = function ($scope, $tim this['snapOptions']['mode'] = oVmap['properties']['snapping']['defaut_snapp_mode']; this['snapOptions']['limit'] = oVmap['properties']['snapping']['defaut_limit']; this['snapOptions']['visible'] = oVmap['properties']['snapping']['defaut_visibility']; + this['snapOptions']['avoidIntersections'] = {}; } /** @@ -373,6 +374,16 @@ nsVmap.nsToolsManager.Select.prototype.selectController = function ($scope, $tim */ this['tmpSnapOptions'] = angular.copy(this['snapOptions']); + /** + * Queryable Business Objects + */ + this['aQueryableBOs'] = []; + + /** + * Business objects avaliable for avoiding intersections + */ + $scope['aAvoidIntersectionsBOs'] = []; + /** * Tree resulting the various GetFeatureInfo requests */ @@ -523,7 +534,21 @@ nsVmap.nsToolsManager.Select.prototype.selectController = function ($scope, $tim features: this.oOverlayFeatures_ }); - this.modify_.on('modifyend', function () { + this.modify_.on('modifyend', function (evt) { + + // Récupère la feature ajoutée + var aFeatures = evt.features.getArray(); + + console.log("evt: ", evt); + console.log("aFeatures: ", aFeatures); + + // Évite les intersections avec les autres couches si besoin + for (var i = 0; i < aFeatures.length; i++) { + this_.avoidIntersections(aFeatures[i]).then(function(){ + console.log('2'); + }); + } + setTimeout(function () { this_.putFeaturesOnTheElement(this_.oOverlayFeatures_.getArray()); }); @@ -685,6 +710,44 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.loadQueryableB }); }; +/** + * Load this.aAvoidIntersectionsBOs + * + */ +nsVmap.nsToolsManager.Select.prototype.selectController.prototype.loadAvoidIntersectionBos = function () { + oVmap.log('nsVmap.nsToolsManager.Select.selectController.loadAvoidIntersectionBos'); + + var this_ = this; + + // Types de géométries pour le calcul des jointures + var aActiveGeomTypes = ['POLYGON', 'MULTIPOLYGON', 'GEOMETRY', 'GEOMETRYCOLLECTION']; + + // Objets métiers actifs pour la calcul des jointures + this.$scope_['aAvoidIntersectionsBOs'] = []; + + console.log("this['editableFeatureType']: ", this['editableFeatureType']); + console.log("this['aQueryableBOs']: ", this['aQueryableBOs']); + + if (goog.isDefAndNotNull(this['editableFeatureType'])) { + + // Si la couche en cours d'insertion est dans aActiveGeomTypes + if (aActiveGeomTypes.indexOf(this['editableFeatureType']) !== -1) { + for (var i = 0; i < this['aQueryableBOs'].length; i++) { + + // Si la couche cible est dans aActiveGeomTypes + if (goog.isDefAndNotNull(this['aQueryableBOs'][i]['bo_geom_type'])) { + if(aActiveGeomTypes.indexOf(this['aQueryableBOs'][i]['bo_geom_type']) !== -1){ + + this.$scope_['aAvoidIntersectionsBOs'].push(this['aQueryableBOs'][i]); + } + } + } + } + } + + console.log("this.$scope_['aAvoidIntersectionsBOs']: ", this.$scope_['aAvoidIntersectionsBOs']); +} + /** * Vérifie que l'échelle en cours respecte les spécification de l'objet métier */ @@ -1880,6 +1943,9 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.editFeature = // Affiche la palette de modification $('#basictools-select-modify-palette').show(); + // Chage le liste des BO intersectables par calcul de polygones jointifs + this_.loadAvoidIntersectionBos(); + // Timeout car lors du toggleOutTools, clearOverlays est lancé setTimeout(function () { // Ajoute la/les feature(s) @@ -2126,12 +2192,160 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.startDrawing = this_.oOverlayLayer_.getSource().addFeature(feature); } + // Évite les intersections avec les autres couches si besoin + this_.avoidIntersections(feature); + // Ajoute les géométries en mode multi ou simple à editableSelection.olFeature this_.putFeaturesOnTheElement(this_.oOverlayFeatures_.getArray()); }); }, this); }; +/** + * Edit the given feature to avoid intersections with layers defined in snapOptions.avoidIntersections + * @param {ol.Feature} olFeature + * @returns {ol.Feature} + */ +nsVmap.nsToolsManager.Select.prototype.selectController.prototype.avoidIntersections = function (olFeature) { + oVmap.log('nsVmap.nsToolsManager.Select.selectController.avoidIntersections'); + + var deferred = this.$q_.defer(); + + // Objets métiers à intersecter + var aIntersectionBos = []; + for (var bo_id in this['snapOptions']['avoidIntersections']) { + if (this['snapOptions']['avoidIntersections'][bo_id] === true) { + aIntersectionBos.push(bo_id); + } + } + + // Remplace la géométrie par celle calculée + if (aIntersectionBos.length > 0) { + this.setDiffGeom_(aIntersectionBos, olFeature).then(function(olFeature){ + console.log('1'); + + deferred.resolve(olFeature); + }); + } + + return deferred.promise; +} + +/** + * Modify the feature geometry to avoid intersections with BOs in aIntersectionBos + * + * @param {string} aIntersectionBos + * @param {ol.Feature} olFeature + * @param {object|undefines} opt_options + */ +nsVmap.nsToolsManager.Select.prototype.selectController.prototype.setDiffGeom_ = function (aIntersectionBos, olFeature, opt_options) { + oVmap.log('nsVmap.nsToolsManager.Select.selectController.setDiffGeom_'); + + if (!goog.isArray(aIntersectionBos)) { + return 0; + } + if (!goog.isDefAndNotNull(olFeature)) { + return 0; + } + if (!goog.isDefAndNotNull(opt_options)) { + opt_options = { + bo_index: 0 + } + } + + var this_ = this; + var deferred = this.$q_.defer(); + var sEWKTGeom = oVmap.getEWKTFromGeom(olFeature.getGeometry()); + + this.getDiffGeom_(aIntersectionBos[opt_options.bo_index], sEWKTGeom).then(function(sNewEWKTGeom){ + + // Remplace la géométrie + olFeature.setGeometry(oVmap.getGeomFromEWKT(sNewEWKTGeom)); + + // Relance la fonction pour les autres objets métiers + opt_options.bo_index ++; + if (opt_options.bo_index < aIntersectionBos.length) { + this_.setDiffGeom_(aIntersectionBos, olFeature, opt_options).then(function(){ + deferred.resolve(olFeature); + }); + } else { + deferred.resolve(olFeature); + } + }, function(err){ + console.log('Cannot get the diff geom: ', err) + }); + + return deferred.promise; +} + +/** + * Get the diff intersection geometry + * + * @param {string} sBoId + * @param {string} sEWKTGeom + * @return {promise} + */ +nsVmap.nsToolsManager.Select.prototype.selectController.prototype.getDiffGeom_ = function (sBoId, sEWKTGeom) { + oVmap.log('nsVmap.nsToolsManager.Select.selectController.getDiffGeom_'); + + console.log("this['editableSelection']: ", this['editableSelection']); + + var oParams = { + 'intersect_geom': sEWKTGeom + }; + + // Filtre pour ne pas s'éviter lui même + if (goog.isDefAndNotNull(this['editableSelection'])) { + if (this['editableSelection']['bo_type'] === sBoId) { + if (goog.isDefAndNotNull(this['editableSelection']['bo_id_field']) && + goog.isDefAndNotNull(this['editableSelection']['bo_id_value'])) { + + oParams['filter'] = { + 'column': this['editableSelection']['bo_id_field'], + 'compare_operator': '!=', + 'value': this['editableSelection']['bo_id_value'] + } + } + } + } + + var deferred = this.$q_.defer(); + ajaxRequest({ + 'method': 'POST', + 'url': oVmap['properties']['api_url'] + '/vmap/querys/' + sBoId + '/diff_geometry', + 'headers': { + 'X-HTTP-Method-Override': 'GET', + 'Accept': 'application/x-vm-json' + }, + 'data': oParams, + 'scope': this.$scope_, + 'success': function (response) { + + if (!goog.isDefAndNotNull(response['data'])) { + deferred.reject('response.data not defined'); + return 0; + } + if (goog.isDefAndNotNull(response['data']['errorMessage'])) { + deferred.reject(response['data']['errorMessage']); + return 0; + } + if (!goog.isDefAndNotNull(response['data'][0])) { + deferred.reject('response.data[0] not defined'); + return 0; + } + if (!goog.isDefAndNotNull(response['data'][0]['diff_geom'])) { + deferred.reject('response.data[0].diff_geom not defined'); + return 0; + } + deferred.resolve(response['data'][0]['diff_geom']); + }, + 'error': function (response) { + deferred.reject(response); + } + }); + return deferred.promise; +} + /** * Put the array of features passed on aFeatures on editableSelection.olFeature with MULTI... form * @param {array} aFeatures @@ -2363,7 +2577,17 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.finishEdition nsVmap.nsToolsManager.Select.prototype.selectController.prototype.showSnappingOptionsModal = function () { oVmap.log('nsVmap.nsToolsManager.Select.prototype.selectController.prototype.showSnappingOptionsModal'); + var this_ = this; this['tmpSnapOptions'] = angular.copy(this['snapOptions']); + + this.$scope_.$applyAsync(function(){ + for (var i = 0; i < this_['aQueryableBOs'].length; i++) { + if (!goog.isDefAndNotNull(this_['tmpSnapOptions']['avoidIntersections'][this_['aQueryableBOs'][i]['bo_id']])) { + this_['tmpSnapOptions']['avoidIntersections'][this_['aQueryableBOs'][i]['bo_id']] = false; + } + } + }); + $('#vmap-select-snap-options-modal').modal('show'); }; @@ -2477,6 +2701,10 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.loadBoVectorSn oBo['bo_snapping_loaded'] = null; return 0; } + if (!goog.isDefAndNotNull(response['data'][0])) { + oBo['bo_snapping_loaded'] = null; + return 0; + } if (response['data'][0]['count'] > this_['snapOptions']['snappingObjectsLimit']) { oBo['bo_snapping_loaded'] = null; var text = 'Limit de points atteinte pour object '; @@ -2489,7 +2717,8 @@ nsVmap.nsToolsManager.Select.prototype.selectController.prototype.loadBoVectorSn if (goog.isDefAndNotNull(response['data'][i]['geom'])) { geom = response['data'][i]['geom']; aFeatures.push(new ol.Feature({ - geometry: oVmap.getGeomFromEWKT(geom) + geometry: oVmap.getGeomFromEWKT(geom), + 'bo_id': bo_id })); } } diff --git a/src/module_vmap/module/template/tools/select.html b/src/module_vmap/module/template/tools/select.html index 420c5b37e81360aa9fd3fcd128e1d46bb3f5e001..bb60aa4908a53e3fc0035c00f3d5a77a323a061b 100644 --- a/src/module_vmap/module/template/tools/select.html +++ b/src/module_vmap/module/template/tools/select.html @@ -290,32 +290,72 @@ <h4 class="modal-title" data-translate="TITLE_SNAPPING_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h4> </div> <div class="modal-body modal-body-big-with-footer-3 font-12"> - <div class="col-sm-6"> - <h5 data-translate="FORM_SNAPPING_DEFAUT_TYPE_ACC_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> - <select class="form-control" - ng-model="ctrl.tmpSnapOptions.mode"> - <option value="segment_edge_node" data-translate="FORM_SNAPPING_METHOD_SEN_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> - <option value="edge_node" data-translate="FORM_SNAPPING_METHOD_EN_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> - <option value="node" data-translate="FORM_SNAPPING_METHOD_N_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> - </select> - </div> - <div class="col-sm-6"> - <h5 data-translate="FORM_SNAPPING_DEFAUT_TOLERANCE_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> - <input type="number" class="form-control" ng-model="ctrl.tmpSnapOptions.tolerance"> - </div> - <div class="col-sm-6"> - <h5 data-translate="FORM_SNAPPING_DEFAUT_LIMIT_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> - <input type="number" class="form-control" ng-model="ctrl.tmpSnapOptions.limit"> + <div class="row"> + <div class="col-sm-6"> + <h5 data-translate="FORM_SNAPPING_TYPE_ACC_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> + <select class="form-control" + ng-model="ctrl.tmpSnapOptions.mode"> + <option value="segment_edge_node" data-translate="FORM_SNAPPING_METHOD_SEN_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> + <option value="edge_node" data-translate="FORM_SNAPPING_METHOD_EN_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> + <option value="node" data-translate="FORM_SNAPPING_METHOD_N_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></option> + </select> + </div> + <div class="col-sm-6"> + <h5 data-translate="FORM_SNAPPING_TOLERANCE_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> + <input type="number" class="form-control" ng-model="ctrl.tmpSnapOptions.tolerance"> + </div> </div> - <div class="col-sm-6"> - <h5 data-translate="FORM_SNAPPING_DEFAUT_VISIBILITY_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> - <div class="radio radio-inline"> - <input type="radio" name="vmap_select_snap_visible" id="vmap_select_snap_visible_1" ng-model="ctrl.tmpSnapOptions.visible" ng-value="true"> - <label for="vmap_select_snap_visible_1">Oui</label> + <div class="row"> + <div class="col-sm-6"> + <h5 data-translate="FORM_SNAPPING_LIMIT_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> + <input type="number" class="form-control" ng-model="ctrl.tmpSnapOptions.limit"> </div> - <div class="radio radio-inline"> - <input type="radio" name="vmap_select_snap_visible" id="vmap_select_snap_visible_2" ng-model="ctrl.tmpSnapOptions.visible" ng-value="false"> - <label for="vmap_select_snap_visible_2">Non</label> + <div class="col-sm-6"> + <h5 data-translate="FORM_SNAPPING_VISIBILITY_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> + <div class="radio radio-inline"> + <input type="radio" name="vmap_select_snap_visible" id="vmap_select_snap_visible_1" ng-model="ctrl.tmpSnapOptions.visible" ng-value="true"> + <label for="vmap_select_snap_visible_1">Oui</label> + </div> + <div class="radio radio-inline"> + <input type="radio" name="vmap_select_snap_visible" id="vmap_select_snap_visible_2" ng-model="ctrl.tmpSnapOptions.visible" ng-value="false"> + <label for="vmap_select_snap_visible_2">Non</label> + </div> + </div> + </div> + <div class="row"> + <div class="col-sm-6"> + <div class="row"> + <div class="col-sm-5"> + + </div> + <div class="col-sm-7"> + <h5 data-translate="FORM_SNAPPING_AVOID_INTERSECTIONS_CONFIGURATION_CONFIGURATION_VMAP_CONFIG"></h5> + </div> + </div> + <div class="row" + ng-repeat="bo in aAvoidIntersectionsBOs"> + <div class="col-sm-5 text-right"> + <label>{{bo.bo_title}}</label> + </div> + <div class="col-sm-7 text-right"> + <div class="radio radio-inline"> + <input type="radio" + name="vmap_select_snap_avoid_intersections_{{$index}}" + id="vmap_select_snap_avoid_intersections_1_{{$index}}" + ng-model="ctrl.tmpSnapOptions.avoidIntersections[bo.bo_id]" + ng-value="true"> + <label for="vmap_select_snap_avoid_intersections_1_{{$index}}">Oui</label> + </div> + <div class="radio radio-inline"> + <input type="radio" + name="vmap_select_snap_avoid_intersections_{{$index}}" + id="vmap_select_snap_avoid_intersections_2_{{$index}}" + ng-model="ctrl.tmpSnapOptions.avoidIntersections[bo.bo_id]" + ng-value="false"> + <label for="vmap_select_snap_avoid_intersections_2_{{$index}}">Non</label> + </div> + </div> + </div> </div> </div> </div> diff --git a/src/module_vmap/web_service/ws/Querys.class.inc b/src/module_vmap/web_service/ws/Querys.class.inc index 1850b33bc8ca8c20fe975b0501c3a908c5b3baa4..06feadba2129a5183d4d0ea55ff91677d639b9c7 100644 --- a/src/module_vmap/web_service/ws/Querys.class.inc +++ b/src/module_vmap/web_service/ws/Querys.class.inc @@ -1289,6 +1289,7 @@ class Querys extends Vmap { $sSchema = $oBusinessObject->aFields['schema']; $sTable = $oBusinessObject->aFields['table']; $sIntersectGeom = $this->aValues['intersect_geom']; + $sInputFilter = $this->aValues['filter']; // Paramètres retenus dans le business object $sGeomColumn = $oBusinessObject->aFields['geom_column']; @@ -1321,6 +1322,11 @@ class Querys extends Vmap { ), 'value' => $sIntersectGeom ); + + if (!empty($sInputFilter)) { + $aFilter = $this->addFilterOperator($sInputFilter, $aFilter); + } + $aDecodedFilter = $this->decodeJSONFilter($aFilter, $sSchema, $sTable); $sSecuredFilter = $aDecodedFilter['request'];