'use strict';
define(function() {
  var gcelement = function(
    EditRulesFactory,
    ogcFactory,
    EditTypesFactory,
    gcStyleFactory,
    gclayers,
    SelectManager,
    $translate,
    gcInteractions
  ) {
    return {
      templateUrl:
        'js/XG/widgets/mapapp/bizedition/views/bizedittransform.html',
      restrict: 'E',
      scope: {
        map: '=map',
        selectfti: '=selectfti',
        editdescription: '=editdescription',
        menuContext: '=menucontext',
        isActive: '=isactive',
        toolbarwidget: '=?toolbarwidget',
        createeditdescription: '&',
        reset: '&',
      },

      link: function(scope, element, attrs, ctrl) {
        scope.isActive = false;
        var format = new ol.format.GeoJSON();
        var map = scope.map;

        /*SelectionMode: outil utilisé pour sélectionner les objets à éditer
                  normal: dessin d'un cadre
                  polygon: dessin d'un polygon
                  query; récupération d'une sélection courante (après l'utilisation du requeteur)
                */
        scope.selectionMode = { value: 'normal' };

        scope.selectionType = { value: 'add' };

        scope.snapState = { isOn: false };

        map.on('snapAddedEvent', function(e) {
          scope.snapState.isOn = true;
          scope.isSomeSnapInteraction = true;
        });
        map.on('snapRemovedEvent', function(e) {
          scope.snapState.isOn = false;
          scope.isSomeSnapInteraction = false;
        });

        scope.isSomeSnapInteraction = false;

        /**
         * [updateBtns mise à jour des boutons de rotation et d'homothocie aprés chaque action de transformation]
         * @param  {undefined} geomBox  [description]
         * @param  {undefined} featRot  [description]
         * @param  {undefined} featHom1 [description]
         * @param  {undefined} featHom2 [description]
         * @param  {undefined} featHom3 [description]
         * @param  {undefined} featDef1 [description]
         * @param  {undefined} featDef2 [description]
         * @param  {undefined} featDef3 [description]
         * @param  {undefined} featDef4 [description]
         * @return {undefined}          [description]
         */
        function updateBtns(
          geomBox,
          featRot,
          featHom1,
          featHom2,
          featHom3,
          featDef1,
          featDef2,
          featDef3,
          featDef4
        ) {
          // recupérer les coordonnées (aprés transformation) du premier point du polygon box correspondant au point de rotation
          var coordPoint0Box = geomBox.getCoordinates()[0][0];
          // recupérer les coordonnées (aprés transformation) des différents points de la box correspondant au points homothétiques
          var coordPoint1Box = geomBox.getCoordinates()[0][1];
          var coordPoint2Box = geomBox.getCoordinates()[0][2];
          var coordPoint3Box = geomBox.getCoordinates()[0][3];
          var coordPoint4Box = [
            (coordPoint0Box[0] + coordPoint1Box[0]) / 2,
            (coordPoint0Box[1] + coordPoint1Box[1]) / 2,
          ];
          var coordPoint5Box = [
            (coordPoint1Box[0] + coordPoint2Box[0]) / 2,
            (coordPoint1Box[1] + coordPoint2Box[1]) / 2,
          ];
          var coordPoint6Box = [
            (coordPoint2Box[0] + coordPoint3Box[0]) / 2,
            (coordPoint2Box[1] + coordPoint3Box[1]) / 2,
          ];
          var coordPoint7Box = [
            (coordPoint0Box[0] + coordPoint3Box[0]) / 2,
            (coordPoint0Box[1] + coordPoint3Box[1]) / 2,
          ];
          // mise à jour du btn de rotation
          featRot.getGeometry().setCoordinates(coordPoint0Box);
          // mise à jour des btns homothetic
          featHom1.getGeometry().setCoordinates(coordPoint1Box);
          featHom2.getGeometry().setCoordinates(coordPoint2Box);
          featHom3.getGeometry().setCoordinates(coordPoint3Box);
          featDef1.getGeometry().setCoordinates(coordPoint4Box);
          featDef2.getGeometry().setCoordinates(coordPoint5Box);
          featDef3.getGeometry().setCoordinates(coordPoint6Box);
          featDef4.getGeometry().setCoordinates(coordPoint7Box);
        }

        if (!('remove' in Element.prototype)) {
          Element.prototype.remove = function() {
            if (this.parentNode) {
              this.parentNode.removeChild(this);
            }
          };
        }

        //Retire l'indication de mesure.
        function resetMeasToolTip() {
          if (scope.transTooltipElement != null) {
            scope.transTooltipElement.remove();
          }
          scope.transTooltipElement = null;
          if (scope.transTooltip) map.addOverlay(scope.transTooltip);
        }
        /**
         * [sqr calculer le carré d'un nombre]
         * @param  {number} a [le nombre]
         * @return {number}
         */
        function sqr(a) {
          return a * a;
        }
        function sign(x) {
          // Si x vaut NaN, le résultat vaudra NaN.
          // Si x vaut -0, le résultat vaudra -0.
          // Si x vaut +0, le résultat vaudra +0.
          // Si x est négatif et différent de -0, le résultat vaudra -1.
          // Si x est positif et différent de +0, le résultat vaudra +1.
          x = +x; // on convertit la valeur en un nombre
          if (x === 0 || isNaN(x)) {
            return Number(x);
          }
          return x > 0 ? 1 : -1;
        }

        /**
         * [calculateAng calcul de l'angle à partir de 3 points]
         * @param  {Array.<number>} coordinates [tableau des coordonnées des 3 points ]
         * @return {string}    [angle en degré]
         */
        function calculateAng(coordinates) {
          var radian = 0;
          var rad = 0;
          if (coordinates.length >= 3) {
            var coordA = coordinates[coordinates.length - 3];
            var coordB = coordinates[coordinates.length - 2];
            var coordC = coordinates[coordinates.length - 1];
          }
          var uX = coordA[0] - coordB[0];
          var uY = coordA[1] - coordB[1];
          var vX = coordC[0] - coordB[0];
          var vY = coordC[1] - coordB[1];
          var normU = Math.sqrt(sqr(uX) + sqr(uY));
          var normV = Math.sqrt(sqr(vX) + sqr(vY));
          var scalUV = uX * vX + uY * vY;
          var cosAng = scalUV / (normU * normV);
          // radian = Math.sign(uX*vY-uY*vX)*Math.acos(cosAng);
          rad = (sign(uX * vY - uY * vX) * Math.acos(cosAng) * 180) / Math.PI;

          radian = Math.round(rad * 100) / 100;
          // Pour avoir la valeur de l'angle toujours positive
          if (radian < 0) radian = 360 + radian;

          return radian + '°';
        }

        /**
         * [createMeasTooltip cree un nouveau outil de mesure]
         * @return {undefined}
         */
        function createMeasTooltip() {
          if (scope.transTooltipElement) {
            scope.transTooltipElement.parentNode.removeChild(
              scope.transTooltipElement
            );
          }
          scope.transTooltipElement = document.createElement('div');
          scope.transTooltipElement.className = 'tooltip tooltip-measure';
          scope.transTooltip = new ol.Overlay({
            element: scope.transTooltipElement,
            offset: [0, -15],
            positioning: 'bottom-center',
          });
          map.addOverlay(scope.transTooltip);
        }
        /**********************Rotation functions ************/
        /**
         * [myrotate fonction de rotation]
         * @param {Array.<number>} flatCoordinates Flat coordinates.
         * @param {number} offset Offset.
         * @param {number} end End.
         * @param {number} stride Stride.
         * @param {number} angle Angle.
         * @param {Array.<number>} anchor Rotation anchor point.
         * @param {Array.<number>=} opt_dest Destination.
         * @return {Array.<number>} Transformed coordinates.
         */
        function myrotate(
          flatCoordinates,
          offset,
          end,
          stride,
          angle,
          anchor,
          opt_dest
        ) {
          var dest = opt_dest ? opt_dest : [];
          var cos = Math.cos(angle);
          var sin = Math.sin(angle);
          var anchorX = anchor[0];
          var anchorY = anchor[1];
          var i = 0;
          for (var j = offset; j < end; j += stride) {
            var deltaX = flatCoordinates[j] - anchorX;
            var deltaY = flatCoordinates[j + 1] - anchorY;
            dest[i++] = anchorX + deltaX * cos - deltaY * sin;
            dest[i++] = anchorY + deltaX * sin + deltaY * cos;
            for (var k = j + 2; k < j + stride; ++k) {
              dest[i++] = flatCoordinates[k];
            }
          }
          return dest;
        }

        /**
         * [myrotate fonction de rotation d'une geometrie]
         * @param  {number} angle     [angle de rotation]
         * @param  {Array.<number>} anchor Rotation anchor point.
         * @param  {undefined} geometryk [description]
         * @return {undefined} [geometrie de l'objet aprés rotation]
         */
        function rotatekis(angle, anchor, geom) {
          // Idem que dans la fonction handle drag event
          // Attention : A modifier avec la version OL3.17.1 => geom.j

          //var flatCoordinates =geom.j;
          var flatCoordinates = geom.B;
          if (flatCoordinates) {
            var stride = 2; // correspond à la GeometryLayout (XY, XYZ, XYM, XYZM) Dans notre cas tjs 2D d'ou stride =2
            geom.j = myrotate(
              flatCoordinates,
              0,
              flatCoordinates.length,
              stride,
              angle,
              anchor,
              flatCoordinates
            );
            geom.changed();
            return geom;
          }
        }
        /**********************Fin Fonctions Rotation*************/
        /**********************Homothécie functions ****************/
        /**
         * [changeCoordinatesForHomothetic calculer les nouvelles coordonnées en fonction du rapport homothétique]
         * @param  {Array.<number>} coordP [tableau des coordonnées de l'élément à transformer]
         * @param  {Array.<number>} anchor    [les coordonnées du point anchor (centre de rotation)]
         * @param  {number} factH     [rapport de l'homothécie ]
         * @return {Array.<number>}   [tableau coordPh des nouvelles coordonnées ]
         */
        function calculateHomotheticCoords(coordP, anchor, factH) {
          var coordPh = [];
          for (var j = 0; j < coordP.length; j++) {
            var coord = [];
            //vecteur composé à partir du point anchor et le point p (le point du polygon à modifier)
            var vectAP = [coordP[j][0] - anchor[0], coordP[j][1] - anchor[1]];
            coord[0] = anchor[0] + vectAP[0] * factH;
            coord[1] = anchor[1] + vectAP[1] * factH;
            //stocker tous les coordonnées du polygon, modifiés par le facteur homothetique dans une tableau dest
            coordPh.push(coord);
          }
          return coordPh;
        }

        /**
         * [getHomotheticCoordsByType det les coordonées modifié par l'homothétie en fonction du type de la géometrie de l'objet]
         * @param  {Array.<number>} coords [coordonnées de la geom]
         * @param  {Array.<number>} anchor    [les coordonnées du point anchor (centre de rotation)]
         * @param  {number} factH     [rapport de l'homothécie ]
         * @param  {string} type   [type de la géometrie]
         * @return {Array.<number>}        [tableau des nouvelles coordonnées]
         */
        function getHomotheticCoordsByType(coords, anchor, factH, type) {
          switch (type) {
            case 'Polygon':
              var coordinates = coords[0];
              var newCoords = calculateHomotheticCoords(
                coordinates,
                anchor,
                factH
              );
              return [newCoords];
              break;
            case 'MultiPolygon':
              var coordinates = coords[0][0];
              var newCoords = calculateHomotheticCoords(
                coordinates,
                anchor,
                factH
              );
              return [[newCoords]];
              break;
            case 'LineString':
              var coordinates = coords;
              var newCoords = calculateHomotheticCoords(
                coordinates,
                anchor,
                factH
              );
              return newCoords;
              break;
            case 'MultiLineString':
              var coordinates = coords[0];
              var newCoords = calculateHomotheticCoords(
                coordinates,
                anchor,
                factH
              );
              return [newCoords];
              break;
            case 'Point':
              var coordinates = coords[0];
              var newCoords = calculateHomotheticCoords(
                coordinates,
                anchor,
                factH
              );
              return [newCoords];
              break;
          }
        }

        /**
         * [geomHomothetic ]
         * @param  {number} factH     [rapport de l'homothécie ]
         * @param  {Array.<number>} anchor    [les coordonnées du point anchor (centre de rotation)]
         * @param  {undefined} geom
         * @return {undefined}   [geometrie de l'objet aprés l'homothétie]
         */
        function geomHomothetic(factH, anchor, geom) {
          var coordinates = geom.getCoordinates();
          var newCoords = getHomotheticCoordsByType(
            coordinates,
            anchor,
            factH,
            geom.getType()
          );
          geom.setCoordinates(newCoords);
          //geom.changed(); // ne fonctionne pas dans ce cas
          return geom;
        }
        /*
         * fonction homthetic utilisé à chaque point de transformation (Hom1, Hom2, Hom3)
         * dans cette fonction le vecteur AB change en fonction du point selectionné pour la trasnformation
         */
        function homthetic(
          evt,
          vectAB,
          newCoordinate,
          anchorCoordinate,
          featureBox,
          featureSelection,
          featureRot,
          featureHom1,
          featureHom2,
          featureHom3,
          featureDef1,
          featureDef2,
          featureDef3,
          featureDef4
        ) {
          var normAB = Math.sqrt(vectAB[0] * vectAB[0] + vectAB[1] * vectAB[1]);
          var vectAC = [
            newCoordinate[0] - anchorCoordinate[0],
            newCoordinate[1] - anchorCoordinate[1],
          ];
          var normACh =
            (vectAB[0] * vectAC[0] + vectAB[1] * vectAC[1]) / normAB;
          var factH = normACh / normAB; // A vérifier // calculer les geometries de la box et du feature selectionné par la fonction d'homothécie
          //A voir
          /*var vectAC2= [firstPointOfEvent[0] - anchorCoordinate[0], firstPointOfEvent[1] - anchorCoordinate[1]];
                            var normACh2 = (vectAB[0]*vectAC2[0] + vectAB[1]*vectAC2[1])/normAB;
                            var factH2 = Math.abs(Math.round((normAB/normACh2)*100)/100) ;
                            fctMeasTransf(evt,featureRot,factH2);*/ var geomBox = geomHomothetic(
            factH,
            anchorCoordinate,
            featureBox.getGeometry()
          );
          var geomSelect = geomHomothetic(
            factH,
            anchorCoordinate,
            featureSelection.getGeometry()
          );
          //mis à jour des geometries en fonction de celles calculés par l'homothécie
          featureBox.setGeometry(geomBox);
          featureSelection.setGeometry(geomSelect);
          // mise à jour des positions des btn de transformation en fonction de la translation effectué
          updateBtns(
            geomBox,
            featureRot,
            featureHom1,
            featureHom2,
            featureHom3,
            featureDef1,
            featureDef2,
            featureDef3,
            featureDef4
          );
        }

        /**********************Fin Fonctions Homothecie*************/
        /**********************Deformation functions ***************/
        /**
         * [calculateDeformationCoords calculer les nouvelles coordonnées en fonction du rapport déformation]
         * @param  {Array.<number>} coordP [tableau des coordonnées de l'élément à transformer]
         * @param  {Array.<number>} vectAB [vecteur composé de l'anchor et du point représentant le feature de déformation]
         * @param  {number} normAB [norme du vecteur AB]
         * @param  {Array.<number>} anchor [anchor Rotation anchor point]
         * @param  {number} factD  [rapport de déformation]
         * @return {Array.<number>}   [tableau des coordonnées aprés déformation]
         */
        function calculateDeformationCoords(
          coordP,
          vectAB,
          normAB,
          anchor,
          factD
        ) {
          var coordPD = [];
          for (var j = 0; j < coordP.length; j++) {
            var coord = [];
            //vecteur composé à partir du point anchor et le point p (le point du polygon à modifier)
            var vectAP = [coordP[j][0] - anchor[0], coordP[j][1] - anchor[1]];
            var vectAPproj1 =
              (vectAB[0] * vectAP[0] + vectAB[1] * vectAP[1]) / normAB;
            var vectAPproj2 =
              (vectAB[0] * vectAP[1] - vectAB[1] * vectAP[0]) / normAB;
            var vectAPproj1Def = vectAPproj1 * factD;
            var vectUxproj1 = vectAB[0] / normAB;
            var vectUxproj2 = vectAB[1] / normAB;
            var APdefx =
              vectAPproj1Def * vectUxproj1 - vectAPproj2 * vectUxproj2;
            var APdefy =
              vectAPproj1Def * vectUxproj2 + vectAPproj2 * vectUxproj1;

            coord[0] = anchor[0] + APdefx;
            coord[1] = anchor[1] + APdefy;
            //stocker tous les coordonnées du polygon, modifiés par le facteur de déformation dans une tableau coordPD
            coordPD.push(coord);
          }
          return coordPD;
        }

        /**
         * [getDeformationCoordsByType det les coordonées modifié par la déformation en fonction du type de la géometrie de l'objet]
         * @param  {Array.<number>} coords [coordonnées de la geom]
         * @param  {Array.<number>} vectAB [vecteur composé de l'anchor et du point représentant le feature de déformation]
         * @param  {number} normAB [norme du vecteur AB]
         * @param  {Array.<number>} anchor [les coordonnées du point anchor (centre de rotation)]
         * @param  {number} factD  [rapport de déformation]
         * @param  {string} type   [type de la géometrie]
         * @return {Array.<number>}        [tableau des nouvelles coordonnées]
         */
        function getDeformationCoordsByType(
          coords,
          vectAB,
          normAB,
          anchor,
          factD,
          type
        ) {
          switch (type) {
            case 'Polygon':
              var coordinates = coords[0];
              var newCoords = calculateDeformationCoords(
                coordinates,
                vectAB,
                normAB,
                anchor,
                factD
              );
              return [newCoords];
              break;
            case 'MultiPolygon':
              var coordinates = coords[0][0];
              var newCoords = calculateDeformationCoords(
                coordinates,
                vectAB,
                normAB,
                anchor,
                factD
              );
              return [[newCoords]];
              break;
            case 'LineString':
              var coordinates = coords;
              var newCoords = calculateDeformationCoords(
                coordinates,
                vectAB,
                normAB,
                anchor,
                factD
              );
              return newCoords;
              break;
            case 'MultiLineString':
              var coordinates = coords[0];
              var newCoords = calculateDeformationCoords(
                coordinates,
                vectAB,
                normAB,
                anchor,
                factD
              );
              return [newCoords];
              break;
            case 'Point':
              var coordinates = coords[0];
              var newCoords = calculateDeformationCoords(
                coordinates,
                vectAB,
                normAB,
                anchor,
                factD
              );
              return [newCoords];
              break;
          }
        }

        /**
         * [geomDeformation mise à jour de la geometrie en fonction des nouveau coordonnées]
         * @param  {Array.<number>} vectAB [vecteur composé de l'anchor et du point représentant le feature de déformation]
         * @param  {number} normAB [norme du vecteur AB]
         * @param  {number} factD  [rapport de déformation]
         * @param  {Array.<number>} anchor [les coordonnées du point anchor (centre de rotation)]
         * @param  {undefined} geom
         * @return {undefined} [geometrie de l'objet aprés la déformation]
         */
        function geomDeformation(vectAB, normAB, factD, anchor, geom) {
          var coordinates = geom.getCoordinates();
          var newCoords = getDeformationCoordsByType(
            coordinates,
            vectAB,
            normAB,
            anchor,
            factD,
            geom.getType()
          );
          geom.setCoordinates(newCoords);
          //geom.changed(); // ne fonctionne pas dans ce cas
          return geom;
        }
        /*
         * fonction deformation utilisé à chaque point de transformation (Def1, Def2, Def3, Def4)
         * dans cette fonction le vecteur AB change en fonction du point selectionné pour la trasnformation
         */
        function deformation(
          vectAB,
          newCoordinate,
          anchorCoordinate,
          featureBox,
          featureSelection,
          featureRot,
          featureHom1,
          featureHom2,
          featureHom3,
          featureDef1,
          featureDef2,
          featureDef3,
          featureDef4
        ) {
          var normAB = Math.sqrt(vectAB[0] * vectAB[0] + vectAB[1] * vectAB[1]);
          var vectAC = [
            newCoordinate[0] - anchorCoordinate[0],
            newCoordinate[1] - anchorCoordinate[1],
          ];
          var normACh =
            (vectAB[0] * vectAC[0] + vectAB[1] * vectAC[1]) / normAB;
          var factH = normACh / normAB;

          // calculer les geometries de la box et du feature selectionné par la fonction d'homothécie
          var geomBox = geomDeformation(
            vectAB,
            normAB,
            factH,
            anchorCoordinate,
            featureBox.getGeometry()
          );
          var geomSelect = geomDeformation(
            vectAB,
            normAB,
            factH,
            anchorCoordinate,
            featureSelection.getGeometry()
          );
          //mis à jour des geometries en fonction de celles calculés par l'homothécie
          featureBox.setGeometry(geomBox);
          featureSelection.setGeometry(geomSelect);

          // mise à jour des positions des btn de transformation en fonction de la translation effectué
          updateBtns(
            geomBox,
            featureRot,
            featureHom1,
            featureHom2,
            featureHom3,
            featureDef1,
            featureDef2,
            featureDef3,
            featureDef4
          );
        }

        /**
         * Handler de la case à cocher permettant d'activer ou de desactiver l'interaction de snap
         * (si la règle métier exécutée à l'initialisation à ajouter une interaction de snap)
         * @returns {undefined}
         */
        scope.switchSnap = function() {
          var isSnap = false;
          var inters = map.getInteractions().getArray();
          for (var i = 0; i < inters.length; i++) {
            if (inters[i] instanceof ol.interaction.Snap) {
              inters[i].setActive(scope.snapState.isOn);
              //scope.editdescription.interactions[i].set("pixelTolerance_",50);
              isSnap = true;
              break;
            }
          }
          if (!isSnap) scope.snapState.isOn = !scope.snapState.isOn;
        };

        scope.selectedFeatures = [];

        var noResultMsg = 'No Result';
        $translate('bizedition.attributesPopupNoResult').then(function(res) {
          noResultMsg = res;
        });

        /**
         * Méthode appelée au clic sur le bouton correspondant à cette directive.
         * @returns {undefined}
         */
        scope.startAction = function() {
          scope.reset();
          //Activation si désactivé et desactivation si activé
          //(la mise à jour de isActive n'a pas encore eu lieu à ce niveau,
          //on a ici encore la valeur de 'isactive' tel qu'elle était avant l'appel de reset() )
          scope.isActive = !scope.isActive;
          draw.setActive(scope.isActive);
          if (scope.isActive) {
            //console.log(scope.menuContext);
            if (scope.menuContext && scope.menuContext.length > 2) {
              scope.menuContext.splice(0, scope.menuContext.length - 2);
            }
          }
          dragBox.setActive(scope.isActive);
          if (!scope.isActive) {
            return;
          }

          scope.selectedFeatures = []; //.splice(0);

          scope.editdescription = scope.createeditdescription();
          if(scope.editdescription === undefined) return;
          scope.editdescription.editType =
            EditTypesFactory.editTypes.update.name;
          scope.editdescription.fti = scope.selectfti;

          scope.selectfeaturesToUpdate();
        };

        /**
         * Active une méthode de sélection de features
         * @returns {undefined}
         */
        scope.selectfeaturesToUpdate = function() {
          //Si option de sélection de features par dessin d'un polygone
          if (scope.selectionMode.value == 'polygon') {
            map.removeInteraction(dragBox);
            gcInteractions.setCurrentToolBar(scope.toolbarwidget);
            map.addInteraction(draw);
            //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
            scope.editdescription.interactions.push(draw);
          } else if (scope.selectionMode.value == 'query') {
            map.removeInteraction(dragBox);
            map.removeInteraction(draw);
            var res = {};
            res.data = SelectManager.getFeaturesByftiType(scope.selectfti.name);
            onSelectionResult(res);
          } else {
            map.removeInteraction(draw);
            gcInteractions.setCurrentToolBar(scope.toolbarwidget);
            map.addInteraction(dragBox);
            //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
            scope.editdescription.interactions.push(dragBox);
          }
        }; //end select



        var dragBox = new ol.interaction.DragBox({
          condition: function(evt) {
            //MacEnvironments don't get here because the event is not
            //recognized as mouseEvent on Mac by the google closure.
            //We have to use the apple key on those devices
            return (
              evt.originalEvent.ctrlKey || scope.isActive
            ); /* ||
                      (gaBrowserSniffer.mac && evt.originalEvent.metaKey);*/
          },
          style: gcStyleFactory.getStyle('selectrectangle'),
        });
        dragBox.set('gctype', 'kis');
        dragBox.set('interaction', 'Select');
        dragBox.set('widget', 'Edition');

        //Interaction de dessin d'un cadre pour sélectionner des features sur la carte.
        var draw = new ol.interaction.Draw({
          type: 'Polygon',
        });
        draw.set('gctype', 'kis');
        draw.set('interaction', 'Draw');
        draw.set('widget', 'Edition');
        draw.setActive(scope.isActive);
        dragBox.setActive(scope.isActive);
        //Interaction de dessin d'un polygone pour sélectionner des features sur la carte.
        dragBox.on('boxend', function(evt) {
          //Réinitialisation préalable si l'interaction dragBox n'a pas été rétirée et que l'utilisateur a la possibilité de refaire une sélection sur la carte.
          //if (scope.editdescription && scope.editdescription.editedfeature) gclayers.getDrawLayer().getSource().removeFeature(scope.editdescription.editedfeature);
          //if (scope.modifyInteraction) map.removeInteraction(scope.modifyInteraction);
          if (scope.p != undefined && scope.p.element != null)
            scope.p.destroy();

          //Recherche des objets intersectés par le polygone de sélection
          const extent = dragBox.getGeometry().getExtent();
          const srid = map.getView().getProjection().getCode();
          //Résultat de la sélection
          ogcFactory.findIntersectedFeaturesByRectangle(extent, srid,
            scope.editdescription.fti.uid, 'edition').then(
            onSelectionResult,
            error => {
              console.error(
                'select feature() ogcFactory.getfeatures, error:' + error
              );
              require('toastr').error(error);
            });
        }); //en dragBox.end

        /**
         * Handler de fin de dessin de polygone de sélection d'objet sur la carte.
         * Permetr de requeter les objets features de la couche sélectionnée, situés à l'intérieur du dessin.
         */
        draw.on('drawend', function(evt) {
          //Fermeture de l'eventuelle popup déjà ouverte.
          if (scope.p != undefined && scope.p.element != null)
            scope.p.destroy();

          //if (scope.modifyInteraction) map.removeInteraction(scope.modifyInteraction);
          //Récupération de la géométrie dessinée
          const polygon = evt.feature.getGeometry();
          const srid = map.getView().getProjection().getCode();
          ogcFactory.findIntersectedFeaturesByPolygon(polygon, srid, scope.editdescription.fti.uid).then(
            onSelectionResult,
            error => {
              console.error('ogcFactory.getfeatures, error:' + error);
              require('toastr').error(error);
            });
        });

        /**
         * Utilitaire: indique si le feature passé en paramètre appartient déjà à la sélection.
         * @param {type} feature
         * @returns {Boolean}
         */
        function isFeatureToAdd(feature) {
          for (var i = 0; i < scope.selectedFeatures.length; i++) {
            if (feature.getId() == scope.selectedFeatures[i].getId()) {
              return false;
            }
          }
          return true;
        }

        /* var objDist = {
                        x : 0,
                        y : 0,
                        angle : 0
                    };*/
        function onSelectionResult(res) {
          //Instanciation de l'objet editdescription à chaque nouvelle sélection si on veut prendre en compte
          //dynamiquement les changement de type de sélection
          //                    scope.createeditdescription();
          //                    scope.editdescription.editType = EditTypesFactory.editTypes.update.name;
          //                    scope.editdescription.fti = scope.selectfti;
          //                    //Enregistrement de la reference vers l'interaction pour la retirer de la carte au besoin.
          //                    scope.editdescription.interactions.push(dragBox);
          require('toastr').clear();
          if (res.data.features == undefined || res.data.features.length == 0) {
            require('toastr').warning(noResultMsg);
            return;
          }

          gclayers
            .getDrawLayer()
            .getSource()
            .clear();
          map.removeLayer(scope.layerBox);
          map.removeLayer(scope.layerRot);
          map.removeLayer(scope.layerHom1);
          map.removeLayer(scope.layerHom2);
          map.removeLayer(scope.layerHom3);
          map.removeLayer(scope.layerDef1);
          map.removeLayer(scope.layerDef2);
          map.removeLayer(scope.layerDef3);
          map.removeLayer(scope.layerDef4);

          //Decodage de la featureCollection, (le decodage retourne un tableau de ol.feature)
          // if (scope.selectionType.value == "new"){

          scope.selectedFeatures = format.readFeatures(res.data.features[0]);
          //}
          //Si la sélection actuelle d'objets doit s'ajouter à la précedente sélection
          /*  else if (scope.selectionType.value == "add"){
                        //Récupération de la nouvelle sélection
                        var partialSelection = format.readFeatures(res.data);
                        //Filtrage pour ne récupérer que des nouveaux features non précedement sélectionnés
                        partialSelection = partialSelection.filter(isFeatureToAdd);
                        //Ajout des nouveaux features à la sélection
                        scope.selectedFeatures = scope.selectedFeatures.concat(partialSelection);
                    }
                    //Par defaut, nouvelle sélection
                    else{
                        scope.selectedFeatures = format.readFeatures(res.data);
                    }  */

          //Mise en evidence des features sélectionnés
          gclayers.getselectSource().clear();
          gclayers.getselectSource().addFeatures(scope.selectedFeatures);

          //Suppression des eventuels precedents features presents dans editDescription
          scope.editdescription.editedfeature = undefined;
          scope.editdescription.relatedfeatures.splice(0);
          scope.editdescription.shareObjects.splice(0);

          //EditDescription: On ne prend en compte qu'un seul objet, le premier sélectionné.
          if (scope.selectedFeatures.length == 1) {
            scope.fCollection = new ol.Collection();

            scope.editdescription.editedfeature = scope.selectedFeatures[0];
            if (scope.isCopy == true) {
              scope.editdescription.editType = 'add';
              scope.editdescription.editedfeature.setId(undefined);
            } else {
              scope.editdescription.editType = 'update';
            }
            scope.fCollection.push(scope.editdescription.editedfeature);
            //Visualisation
            gclayers
              .getDrawLayer()
              .getSource()
              .addFeature(scope.editdescription.editedfeature);

            if (
              scope.editdescription.editedfeature.getGeometry().getType() !==
              'Point'
            ) {
              /*************Create Box transformation***********/

              // Style de la box de trasformation
              var stylesBox = [
                new ol.style.Style({
                  stroke: new ol.style.Stroke({
                    color: 'black',
                    width: 1,
                  }),
                  fill: new ol.style.Fill({
                    color: 'rgba(255,255,255, 0.1)',
                  }),
                }),
                new ol.style.Style({
                  image: new ol.style.Circle({
                    radius: 1,
                    stroke: new ol.style.Stroke({
                      color: 'black',
                    }),
                    fill: new ol.style.Fill({
                      color: '#ddd',
                    }),
                  }),
                  geometry: function(feature) {
                    // return the coordinates of the first ring of the polygon
                    var coordinates = feature.getGeometry().getCoordinates()[0];
                    return new ol.geom.MultiPoint(coordinates);
                  },
                }),
              ];

              // recuperer l'extent du feature selectionné
              var ext = scope.editdescription.editedfeature
                .getGeometry()
                .getExtent();


              //créer la geometrie de la box à partir de l'extent

              var box = new ol.geom.Polygon.fromExtent(ext);
              // Agrandir la box autour de l'objet selectionné
              box.scale(1.2);

              //créer le feature représentant la box de transformation
              var featureBox = new ol.Feature({
                geometry: box,
                name: 'MyBox',
              });

              var srcBox = new ol.source.Vector();
              // ajout du feature box à la source
              srcBox.addFeature(featureBox);
              // créer une couche vectorielle de la box
              scope.layerBox = new ol.layer.Vector({
                source: srcBox,
                style: stylesBox,
              });
              // ajouter la couche à la map et visualisation
              map.addLayer(scope.layerBox);


              /*************Create Point rotation***********/

              var stylesRot = [
                new ol.style.Style({
                  image: new ol.style.Circle({
                    radius: 7,
                    stroke: new ol.style.Stroke({
                      color: 'black',
                    }),
                    fill: new ol.style.Fill({
                      color: '#C0C0C0',
                    }),
                  }),
                }),
              ];
              // le point de rotation correspond au premier point de la box
              var poinrtRot = box.getCoordinates()[0][0];
              var featureRot = new ol.Feature({
                geometry: new ol.geom.Point(poinrtRot),
                name: 'MyRot',
              });
              var srcRot = new ol.source.Vector();
              srcRot.addFeature(featureRot);
              scope.layerRot = new ol.layer.Vector({
                source: srcRot,
                style: stylesRot,
              });
              map.addLayer(scope.layerRot);
              /*************Create Points homethetic***********/
              var stylesHom = [
                new ol.style.Style({
                  image: new ol.style.Circle({
                    radius: 4,
                    stroke: new ol.style.Stroke({
                      color: 'black',
                    }),
                    fill: new ol.style.Fill({
                      color: '#E6E6FA ',
                    }),
                  }),
                }),
              ];
              ///create feature homothetic 1
              ///=> coorespond au deuxième point de la box
              var poinrtHom1 = box.getCoordinates()[0][1];
              var featureHom1 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtHom1),
                name: 'Hom1',
              });
              var srcHom1 = new ol.source.Vector();
              srcHom1.addFeature(featureHom1);
              scope.layerHom1 = new ol.layer.Vector({
                source: srcHom1,
                style: stylesHom,
              });
              map.addLayer(scope.layerHom1);
              ///create feature homothetic 2
              ///=> coorespond au troisième point de la box
              var poinrtHom2 = box.getCoordinates()[0][2];
              var featureHom2 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtHom2),
                name: 'Hom2',
              });
              var srcHom2 = new ol.source.Vector();
              srcHom2.addFeature(featureHom2);
              scope.layerHom2 = new ol.layer.Vector({
                source: srcHom2,
                style: stylesHom,
              });
              map.addLayer(scope.layerHom2);
              ///create feature homothetic 3
              ///=> coorespond au quatrième point de la box
              var poinrtHom3 = box.getCoordinates()[0][3];
              var featureHom3 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtHom3),
                name: 'Hom3',
              });
              var srcHom3 = new ol.source.Vector();
              srcHom3.addFeature(featureHom3);
              scope.layerHom3 = new ol.layer.Vector({
                source: srcHom3,
                style: stylesHom,
              });
              map.addLayer(scope.layerHom3);
              ///create feature deformation 1
              ///=> coorespond au point au milieu de la droite composée par le premier (pointde rotation) et le deuxième point de la box
              var coordPointDef1X = (poinrtRot[0] + poinrtHom1[0]) / 2;
              var coordPointDef1Y = (poinrtRot[1] + poinrtHom1[1]) / 2;
              var poinrtDef1 = [coordPointDef1X, coordPointDef1Y];
              var featureDef1 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtDef1),
                name: 'Def1',
              });
              var srcDef1 = new ol.source.Vector();
              srcDef1.addFeature(featureDef1);
              scope.layerDef1 = new ol.layer.Vector({
                source: srcDef1,
                style: stylesHom,
              });
              map.addLayer(scope.layerDef1);
              ///create feature deformation 2
              ///=> coorespond au point au milieu de la droite composée par le deuxième et le troisième point de la box
              var coordPointDef2X = (poinrtHom1[0] + poinrtHom2[0]) / 2;
              var coordPointDef2Y = (poinrtHom1[1] + poinrtHom2[1]) / 2;
              var poinrtDef2 = [coordPointDef2X, coordPointDef2Y];
              var featureDef2 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtDef2),
                name: 'Def2',
              });
              var srcDef2 = new ol.source.Vector();
              srcDef2.addFeature(featureDef2);
              scope.layerDef2 = new ol.layer.Vector({
                source: srcDef2,
                style: stylesHom,
              });
              map.addLayer(scope.layerDef2);

              ///create feature deformation 3
              ///=> coorespond au point au milieu de la droite composée par le troisième et le quatrième point de la box
              var coordPointDef3X = (poinrtHom2[0] + poinrtHom3[0]) / 2;
              var coordPointDef3Y = (poinrtHom2[1] + poinrtHom3[1]) / 2;
              var poinrtDef3 = [coordPointDef3X, coordPointDef3Y];
              var featureDef3 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtDef3),
                name: 'Def3',
              });
              var srcDef3 = new ol.source.Vector();
              srcDef3.addFeature(featureDef3);
              scope.layerDef3 = new ol.layer.Vector({
                source: srcDef3,
                style: stylesHom,
              });
              map.addLayer(scope.layerDef3);

              ///create feature deformation 4
              ///=> coorespond au point au milieu de la droite composée par le premier et le quatrième point de la box
              var coordPointDef4X = (poinrtRot[0] + poinrtHom3[0]) / 2;
              var coordPointDef4Y = (poinrtRot[1] + poinrtHom3[1]) / 2;
              var poinrtDef4 = [coordPointDef4X, coordPointDef4Y];
              var featureDef4 = new ol.Feature({
                geometry: new ol.geom.Point(poinrtDef4),
                name: 'Def4',
              });
              var srcDef4 = new ol.source.Vector();
              srcDef4.addFeature(featureDef4);
              scope.layerDef4 = new ol.layer.Vector({
                source: srcDef4,
                style: stylesHom,
              });
              map.addLayer(scope.layerDef4);

              /*************Debut fonction interaction de transformation***********/

              /**
               * Define a namespace for the application.
               */
              var app = {};

              /**
               * @constructor
               * @extends {ol.interaction.Pointer}
               */
              app.Drag = function() {
                ol.interaction.Pointer.call(this, {
                  handleDownEvent: app.Drag.prototype.handleDownEvent,
                  handleDragEvent: app.Drag.prototype.handleDragEvent,
                  handleMoveEvent: app.Drag.prototype.handleMoveEvent,
                  handleUpEvent: app.Drag.prototype.handleUpEvent,
                });

                /**
                 * @type {ol.Pixel}
                 * @private
                 */

                this.lastCoordinate_ = null;

                /**
                 * @type {string|undefined}
                 * @private
                 */
                this.cursor_ = 'pointer';

                /**
                 * @type {array features}
                 * @private
                 */

                this.features = {
                  box: featureBox,
                  selection: scope.editdescription.editedfeature,
                  rotation: featureRot,
                  hom1: featureHom1,
                  hom2: featureHom2,
                  hom3: featureHom3,
                  def1: featureDef1,
                  def2: featureDef2,
                  def3: featureDef3,
                  def4: featureDef4,
                };

                /**
                 * @type {string|undefined}
                 * @private
                 */
                this.previousCursor_ = undefined;

                /**
                 * @type {string|undefined}
                 * @private
                 */
                this.action = undefined;
              };
              ol.inherits(app.Drag, ol.interaction.Pointer);

              /**
               * @param {ol.MapBrowserEvent} evt Map browser event.
               * @return {boolean} `true` to start the drag sequence.
               */
              app.Drag.prototype.handleDownEvent = function(evt) {
                try {
                  var feature = evt.map.forEachFeatureAtPixel(
                    evt.pixel,
                    function(feature) {
                      return feature;
                    }
                  );

                  //console.log(map.getTarget());
                  if (feature) {
                    // definir l'action de transformation en fonction du feature selectionné
                    if (feature.getProperties().name === 'MyRot') {
                      this.action = 'rotation';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Hom1') {
                      this.action = 'homothetic1';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Hom2') {
                      this.action = 'homothetic2';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Hom3') {
                      this.action = 'homothetic3';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Def1') {
                      this.action = 'deformation1';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Def2') {
                      this.action = 'deformation2';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Def3') {
                      this.action = 'deformation3';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'Def4') {
                      this.action = 'deformation4';

                      this.lastCoordinate_ = evt.coordinate;
                    } else if (feature.getProperties().name === 'MyBox') {
                      this.action = 'translation';
                      this.lastCoordinate_ = evt.coordinate;
                    }
                  }
                  return !!feature;
                } catch (e) {}
              };

              var firstPointOfEvent;
              /**
               * @param {ol.MapBrowserEvent} evt Map browser event.
               */
              app.Drag.prototype.handleDragEvent = function(evt) {
                //if ( !firstPointOfEvent ) firstPointOfEvent = this.lastCoordinate_;
                // Recupération de la geom de la box pour calculer l'anchor (centre de rotation)
                var geom = this.features.box.getGeometry();
                var anchorCoordinate = new ol.extent.getCenter(
                  this.features.box.getGeometry().getExtent()
                );
                var newCoordinate = evt.coordinate;
                // appliquer la rotation si point rotation est selectionné
                if (this.lastCoordinate_ && this.action == 'rotation') {
                  if (!firstPointOfEvent)
                    firstPointOfEvent = this.lastCoordinate_;
                  // calculate vectors of last and current pointer positions
                  var lastVector = [
                    this.lastCoordinate_[0] - anchorCoordinate[0],
                    this.lastCoordinate_[1] - anchorCoordinate[1],
                  ];
                  var newVector = [
                    newCoordinate[0] - anchorCoordinate[0],
                    newCoordinate[1] - anchorCoordinate[1],
                  ];
                  // calculate angle between last and current vectors (positive angle counter-clockwise)
                  var angle = Math.atan2(
                    lastVector[0] * newVector[1] - newVector[0] * lastVector[1],
                    lastVector[0] * newVector[0] + lastVector[1] * newVector[1]
                  );
                  // calculer l'angle d'affichage de la rotation (droite de référence composé entre l'anchor et le premier point de l'evt)
                  var angleDisplay = calculateAng([
                    firstPointOfEvent,
                    anchorCoordinate,
                    newCoordinate,
                  ]);

                  // calculer les geometries de la box et du feature selectionné parla fonction de rotation
                  /* var geomBox = rotatekis(angle,anchorCoordinate ,this.features.box.getGeometry());
                                var geomSelect = rotatekis(angle,anchorCoordinate ,this.features.selection.getGeometry());*/
                  //var geomBox = rotatekis(angle,anchorCoordinate ,this.features.box.getGeometry());
                  //var geomSelect = rotatekis(angle,anchorCoordinate ,this.features.selection.getGeometry());

                  //var geom3 = rotatekis(angle,anchorCoordinate ,_this4.features.rotation.getGeometry());
                  //mis à jour des geometries en fonction de celles calculés par la rotation
                  //this.features.box.setGeometry(geomBox);
                  //this.features.selection.setGeometry(geomSelect);

                  ///// changement rotate function dans la version 3.18.2 (plus besoin de determiner les flat coordinate par :geom.j)
                  ///la fonction rotate est en mode experimentale
                  var geomBox = this.features.box.getGeometry();
                  geomBox.rotate(angle, anchorCoordinate);
                  var geomSelect = this.features.selection.getGeometry();
                  geomSelect.rotate(angle, anchorCoordinate);
                  updateBtns(
                    geomBox,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  fctMeasTransf(evt, this.features.rotation, angleDisplay);

                  //console.log('styleRot',this.features.rotation.getStyle());
                  this.lastCoordinate_ = evt.coordinate;
                }
                //appliquer l'homothecie par le point Hom1
                if (this.lastCoordinate_ && this.action == 'homothetic1') {
                  resetMeasToolTip();
                  var coordHom1 = this.features.hom1
                    .getGeometry()
                    .getCoordinates();
                  if (!firstPointOfEvent) firstPointOfEvent = coordHom1;
                  var vectAB = [
                    coordHom1[0] - anchorCoordinate[0],
                    coordHom1[1] - anchorCoordinate[1],
                  ];

                  homthetic(
                    evt,
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }
                //appliquer l'homothecie par le point  Hom2
                if (this.lastCoordinate_ && this.action == 'homothetic2') {
                  resetMeasToolTip();
                  var coordHom2 = this.features.hom2
                    .getGeometry()
                    .getCoordinates();
                  if (!firstPointOfEvent) firstPointOfEvent = coordHom2;
                  var vectAB = [
                    coordHom2[0] - anchorCoordinate[0],
                    coordHom2[1] - anchorCoordinate[1],
                  ];
                  //var vectAB = [this.lastCoordinate_[0] - anchorCoordinate[0], this.lastCoordinate_[1] - anchorCoordinate[1]];

                  homthetic(
                    evt,
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }
                //appliquer l'homothecie par le point  Hom3
                if (this.lastCoordinate_ && this.action == 'homothetic3') {
                  resetMeasToolTip();
                  var coordHom3 = this.features.hom3
                    .getGeometry()
                    .getCoordinates();
                  if (!firstPointOfEvent) firstPointOfEvent = coordHom3;
                  var vectAB = [
                    coordHom3[0] - anchorCoordinate[0],
                    coordHom3[1] - anchorCoordinate[1],
                  ];

                  homthetic(
                    evt,
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }

                //appliquer la deformation par le point  Def1
                if (this.lastCoordinate_ && this.action == 'deformation1') {
                  resetMeasToolTip();
                  var coordDef1 = this.features.def1
                    .getGeometry()
                    .getCoordinates();
                  var vectAB = [
                    coordDef1[0] - anchorCoordinate[0],
                    coordDef1[1] - anchorCoordinate[1],
                  ];
                  //var vectAB = [this.lastCoordinate_[0] - anchorCoordinate[0], this.lastCoordinate_[1] - anchorCoordinate[1]];

                  deformation(
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }

                //appliquer la deformation par le point  Def2
                if (this.lastCoordinate_ && this.action == 'deformation2') {
                  resetMeasToolTip();
                  var coordDef2 = this.features.def2
                    .getGeometry()
                    .getCoordinates();
                  var vectAB = [
                    coordDef2[0] - anchorCoordinate[0],
                    coordDef2[1] - anchorCoordinate[1],
                  ];
                  //var vectAB = [this.lastCoordinate_[0] - anchorCoordinate[0], this.lastCoordinate_[1] - anchorCoordinate[1]];

                  deformation(
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }

                //appliquer la deformation par le point  Def3
                if (this.lastCoordinate_ && this.action == 'deformation3') {
                  resetMeasToolTip();
                  var coordDef3 = this.features.def3
                    .getGeometry()
                    .getCoordinates();
                  var vectAB = [
                    coordDef3[0] - anchorCoordinate[0],
                    coordDef3[1] - anchorCoordinate[1],
                  ];
                  //var vectAB = [this.lastCoordinate_[0] - anchorCoordinate[0], this.lastCoordinate_[1] - anchorCoordinate[1]];

                  deformation(
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }

                //appliquer la deformation par le point  Def4
                if (this.lastCoordinate_ && this.action == 'deformation4') {
                  resetMeasToolTip();
                  var coordDef4 = this.features.def4
                    .getGeometry()
                    .getCoordinates();
                  var vectAB = [
                    coordDef4[0] - anchorCoordinate[0],
                    coordDef4[1] - anchorCoordinate[1],
                  ];
                  //var vectAB = [this.lastCoordinate_[0] - anchorCoordinate[0], this.lastCoordinate_[1] - anchorCoordinate[1]];

                  deformation(
                    vectAB,
                    newCoordinate,
                    anchorCoordinate,
                    this.features.box,
                    this.features.selection,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_ = evt.coordinate;
                }

                //appliquer la rotation si la box est selectionné
                if (this.lastCoordinate_ && this.action == 'translation') {
                  resetMeasToolTip();
                  //calcul des distances dernières coordonnées et les coordonnées courantes du curseur
                  var deltaX = evt.coordinate[0] - this.lastCoordinate_[0];
                  var deltaY = evt.coordinate[1] - this.lastCoordinate_[1];
                  // mise à jour de la box geom en fonction des distances calculées
                  var geomBox = this.features.box.getGeometry();
                  geomBox.translate(deltaX, deltaY);
                  // mise à jour de la geom du feature à transformer en fonction des distances calculées
                  var geomSelect = this.features.selection.getGeometry();
                  geomSelect.translate(deltaX, deltaY);
                  // mise à jour des positions des btn de transformation en fonction de la translation effectué
                  updateBtns(
                    geomBox,
                    this.features.rotation,
                    this.features.hom1,
                    this.features.hom2,
                    this.features.hom3,
                    this.features.def1,
                    this.features.def2,
                    this.features.def3,
                    this.features.def4
                  );

                  this.lastCoordinate_[0] = evt.coordinate[0];
                  this.lastCoordinate_[1] = evt.coordinate[1];
                }
                scope.$emit('setUpdatesToSave', { value: true });
              };

              /**
               * [fctMeasTransf fct de definition et placement de l'indicateur de transformation]
               * @param  {[type]} evt
               * @param  {undefined} featureTrans [le feature à transformer]
               * @param  {number} transfParam  [parametre de transformation (angle ou facteur d'homothecie)]
               * @return {undefined}
               */
              var fctMeasTransf = function(evt, featureTrans, transfParam) {
                resetMeasToolTip();
                createMeasTooltip();

                if (featureTrans) {
                  var tooltipCoord = evt.coordinate;
                  var output;
                  var geom = featureTrans.getGeometry();
                  if (geom instanceof ol.geom.Point) {
                    output = transfParam;
                    tooltipCoord = geom.getLastCoordinate();
                  }
                  scope.transTooltipElement.innerHTML = output;
                  scope.transTooltip.setPosition(tooltipCoord);
                }
              };

              /**********************Fin Fonctions Deformation************/

              /**
               * @return {boolean} `false` to stop the drag sequence.
               */
              app.Drag.prototype.handleUpEvent = function() {
                // this.lastCoordinate_ = null;
                if (this.lastCoordinate_) {
                  this.lastCoordinate_ = undefined;
                  resetMeasToolTip();

                  return true;
                }
                return false;
              };

              /*************Fin fonction interaction de transformation***********/

              // création d'une interaction de transformation
              scope.interactionTransform = new app.Drag();
              // ajout de l'interaction de transformation à la map
              gcInteractions.setCurrentToolBar(scope.toolbarwidget);
              map.addInteraction(scope.interactionTransform);
            } // end if a feature found in selection
          }
        }
        scope.$on('removeTransformation', function() {
          // supprimer les layers contenant les features box et point rotation
          // appliqué au niveau du reset
          map.removeLayer(scope.layerBox);
          map.removeLayer(scope.layerRot);
          map.removeLayer(scope.layerHom1);
          map.removeLayer(scope.layerHom2);
          map.removeLayer(scope.layerHom3);
          map.removeLayer(scope.layerDef1);
          map.removeLayer(scope.layerDef2);
          map.removeLayer(scope.layerDef3);
          map.removeLayer(scope.layerDef4);
        });

        scope.onModifyEnd = function(clicEvent) {
          //Réactivation des  interactions
          //                    angular.forEach(disabledinteractionsArray, function(value, key) {
          //                        value.setActive(true);
          //                    });

          //map.getView().setZoom(map.getView().getZoom()-1);
          map.un('singleclick', scope.onModifyEnd);

          if (
            (angular.isUndefined(clicEvent) ||
              !clicEvent.originalEvent.shiftKey) &&
            scope.modifyInteraction
          )
            map.removeInteraction(scope.modifyInteraction);

          if (scope.editdescription.editedfeature != undefined) {
            //Execution des règles 'onend'.
            var promise = EditRulesFactory.executeEndRules(
              scope.editdescription,
              scope.editdescription.fti,
              map
            );
            promise.then(
              function() {
                console.info('EditRulesFactory.executeEndRules done.');
              },
              function(errorReason) {
                console.error(
                  'EditRulesFactory.executeEndRules, error:' + errorReason
                );
                require('toastr').error('executeEndRules error.');
              }
            );
          }
        };
      },
    };
  };

  gcelement.$inject = [
    'EditRulesFactory',
    'ogcFactory',
    'EditTypesFactory',
    'gcStyleFactory',
    'gclayers',
    'SelectManager',
    '$translate',
    'gcInteractions'
  ];
  return gcelement;
});
