From 23dca0217c8ef4ce6e02c94c6b71b7f9fa14d163 Mon Sep 17 00:00:00 2001 From: Emilie Genton Date: Fri, 12 Jan 2024 11:28:58 +0100 Subject: [PATCH] =?UTF-8?q?Permet=20de=20choisir=20le=20r=C3=A9seau=20pour?= =?UTF-8?q?=20une=20simulation=20de=20la=20couverture=20hydraulique...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... Soit le réseau commun, soit celui importé soit les 2. Issue: #202719 Change-Id: I417cc467ea7ea2765905cb5e98d0f252db864118 --- .../planification_deci/OlMapEtude.vue | 35 +- .../fr/sdis83/remocra/GlobalConstants.java | 12 - .../fr/sdis83/remocra/data/ParametreData.java | 4 + .../remocra/domain/remocra/ParamConf.java | 1 + .../CouvertureHydrauliqueRepository.java | 10 +- .../CouvertureHydrauliqueUseCase.java | 37 +- .../web/CouvertureHydrauliqueController.java | 8 +- .../postgres/remocra_db/patches/194/194.sql | 418 ++++++++++++++++++ 8 files changed, 485 insertions(+), 40 deletions(-) create mode 100644 server/sdis-remocra/home/postgres/remocra_db/patches/194/194.sql diff --git a/client-ng/src/components/planification_deci/OlMapEtude.vue b/client-ng/src/components/planification_deci/OlMapEtude.vue index 3b3301d6d..fd1d458ac 100644 --- a/client-ng/src/components/planification_deci/OlMapEtude.vue +++ b/client-ng/src/components/planification_deci/OlMapEtude.vue @@ -17,15 +17,15 @@

Souhaitez-vous calculer la couverture hydraulique de cet hydrant sur le réseau routier commun ou sur le réseau routier précédemment importé ?

+
+ Commun + Importé + Commun et importé +
@@ -555,7 +555,7 @@ export default { }) }, - calculCouvertureHydraulique(reseauImporte) { + calculCouvertureHydraulique(reseauImporte, reseauImporteWithCourant = false) { this.spinnerMap = true; this.disableToolbar = true; @@ -580,6 +580,7 @@ export default { formData.append("hydrantsProjet", JSON.stringify({projets})); formData.append("etude", this.idEtude); formData.append("reseauImporte", reseauImporte); + formData.append("reseauImporteWithCourant", reseauImporteWithCourant); axios.post('/remocra/couverturehydraulique/calcul', formData, { headers: { @@ -591,6 +592,8 @@ export default { this.$nextTick(() => { this.$root.$options.bus.$emit(eventTypes.OLMAP_COUCHES_REFRESHLAYER); }); + + this.$bvModal.hide("modaleChoixReseau"); }).catch(() => { this.disableToolbar = false; this.spinnerMap = false; @@ -682,4 +685,22 @@ export default { text-indent: 5%; font-family: Segoe UI,Roboto,Helvetica,Arial; } + +.buttonChoixReseau { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.buttonChoixReseau .btn { + background-color: transparent; + margin-left: 10px; +} + +.buttonChoixReseau .btn:hover { + background-color: #007bff; + color: white; + margin-left: 10px; +} diff --git a/remocra/src/main/java/fr/sdis83/remocra/GlobalConstants.java b/remocra/src/main/java/fr/sdis83/remocra/GlobalConstants.java index 010c79836..37b510f06 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/GlobalConstants.java +++ b/remocra/src/main/java/fr/sdis83/remocra/GlobalConstants.java @@ -19,18 +19,6 @@ public class GlobalConstants { */ public static final String CATEGORIE_CRISE = "GESTION_CRISE"; - //////// Couverture hydraulique - /** Clé du param conf correspondant à la profondeur de la couverture hydraulique */ - public static final String PROFONDEUR_COUVERTURE = "PROFONDEUR_COUVERTURE"; - - /** - * Clé du param conf correspondant à la distance maximal de parcours de la couverture hydraulique - */ - public static final String DECI_DISTANCE_MAX_PARCOURS = "DECI_DISTANCE_MAX_PARCOURS"; - - /** Clé du param conf correspondant aux distances à parcourir de la couverture hydraulique */ - public static final String DECI_ISODISTANCES = "DECI_ISODISTANCES"; - /** Champ appartenance dans la table contact */ public static final String GESTIONNAIRE = "GESTIONNAIRE"; diff --git a/remocra/src/main/java/fr/sdis83/remocra/data/ParametreData.java b/remocra/src/main/java/fr/sdis83/remocra/data/ParametreData.java index 8b33b8be4..26bace363 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/data/ParametreData.java +++ b/remocra/src/main/java/fr/sdis83/remocra/data/ParametreData.java @@ -383,6 +383,10 @@ public Integer getDeciDistanceMaxParcours() { return (Integer) this.getValeur(ParamConf.ParamConfParam.DECI_DISTANCE_MAX_PARCOURS.getCle()); } + public Integer getProfondeurCouverture() { + return (Integer) this.getValeur(ParamConf.ParamConfParam.PROFONDEUR_COUVERTURE.getCle()); + } + public String getDeciIsodistances() { return (String) this.getValeur(ParamConf.ParamConfParam.DECI_ISODISTANCES.getCle()); } diff --git a/remocra/src/main/java/fr/sdis83/remocra/domain/remocra/ParamConf.java b/remocra/src/main/java/fr/sdis83/remocra/domain/remocra/ParamConf.java index d17efe6e3..db0d4f7aa 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/domain/remocra/ParamConf.java +++ b/remocra/src/main/java/fr/sdis83/remocra/domain/remocra/ParamConf.java @@ -157,6 +157,7 @@ public static enum ParamConfParam { // DECI DECI_DISTANCE_MAX_PARCOURS("DECI_DISTANCE_MAX_PARCOURS", Integer.class), DECI_ISODISTANCES("DECI_ISODISTANCES", String.class), + PROFONDEUR_COUVERTURE("PROFONDEUR_COUVERTURE", Integer.class), DASHBOARD_BASE_URL("DASHBOARD_BASE_URL", String.class), PROCESS_OFFLINE_USER("PROCESS_OFFLINE_USER", String.class), DOSSIER_ROOT("1_DOSSIER_ROOT", String.class), diff --git a/remocra/src/main/java/fr/sdis83/remocra/repository/CouvertureHydrauliqueRepository.java b/remocra/src/main/java/fr/sdis83/remocra/repository/CouvertureHydrauliqueRepository.java index 46c45116f..ba714d79c 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/repository/CouvertureHydrauliqueRepository.java +++ b/remocra/src/main/java/fr/sdis83/remocra/repository/CouvertureHydrauliqueRepository.java @@ -42,7 +42,8 @@ public void executeInsererJoinctionPei( int distanceMaxAuReseau, Long reseauImporte, List idsHydrant, - List idsHydrantProjet) { + List idsHydrantProjet, + boolean useReseauImporteWithCourant) { context .select( @@ -53,6 +54,8 @@ public void executeInsererJoinctionPei( + distanceMaxAuReseau + ", " + reseauImporte + + ", " + + useReseauImporteWithCourant + ")")) .from(PEI) .where( @@ -72,7 +75,8 @@ public void executeParcoursCouverture( List distances, List idsHydrant, List idsHydrantProjet, - int profondeurCouverture) { + int profondeurCouverture, + boolean useReseauImporteWithCourant) { context .select( DSL.field( @@ -86,6 +90,8 @@ public void executeParcoursCouverture( + distances + ", " + profondeurCouverture + + ", " + + useReseauImporteWithCourant + ")")) .from(PEI) .where( diff --git a/remocra/src/main/java/fr/sdis83/remocra/usecase/couverturehydraulique/CouvertureHydrauliqueUseCase.java b/remocra/src/main/java/fr/sdis83/remocra/usecase/couverturehydraulique/CouvertureHydrauliqueUseCase.java index c9e59c810..4736f2144 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/usecase/couverturehydraulique/CouvertureHydrauliqueUseCase.java +++ b/remocra/src/main/java/fr/sdis83/remocra/usecase/couverturehydraulique/CouvertureHydrauliqueUseCase.java @@ -2,9 +2,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import fr.sdis83.remocra.GlobalConstants; import fr.sdis83.remocra.repository.CouvertureHydrauliqueRepository; -import fr.sdis83.remocra.repository.ParamConfRepository; +import fr.sdis83.remocra.usecase.parametre.ParametreDataProvider; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -20,15 +19,19 @@ public class CouvertureHydrauliqueUseCase { @Autowired CouvertureHydrauliqueRepository couvertureHydrauliqueRepository; - @Autowired ParamConfRepository paramConfRepository; + @Autowired protected ParametreDataProvider parametreDataProvider; private static final Logger logger = LoggerFactory.getLogger(CouvertureHydrauliqueUseCase.class); - private ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper = new ObjectMapper(); public CouvertureHydrauliqueUseCase() {} public void calcul( - String hydrantsExistants, String hydrantsProjet, Long idEtude, Boolean useReseauImporte) { + String hydrantsExistants, + String hydrantsProjet, + Long idEtude, + Boolean useReseauImporte, + Boolean useReseauImporteWithCourant) { List listPei = new ArrayList<>(); List listPeiProjet = new ArrayList<>(); try { @@ -57,28 +60,26 @@ public void calcul( couvertureHydrauliqueRepository.deleteCouverture(idEtude); - int profondeurCouverture = - Integer.parseInt( - paramConfRepository.getByCle(GlobalConstants.PROFONDEUR_COUVERTURE).getValeur()); - int distanceMaxParcours = - Integer.parseInt( - paramConfRepository.getByCle(GlobalConstants.DECI_DISTANCE_MAX_PARCOURS).getValeur()); + int profondeurCouverture = parametreDataProvider.get().getProfondeurCouverture(); + int distanceMaxParcours = parametreDataProvider.get().getDeciDistanceMaxParcours(); List distances = new ArrayList<>(); for (String s : - paramConfRepository - .getByCle(GlobalConstants.DECI_ISODISTANCES) - .getValeur() - .replaceAll(" ", "") - .split(",")) { + parametreDataProvider.get().getDeciIsodistances().replaceAll(" ", "").split(",")) { distances.add(Integer.parseInt(s)); } couvertureHydrauliqueRepository.executeInsererJoinctionPei( - distanceMaxParcours, reseauImporte, listPei, listPeiProjet); + distanceMaxParcours, reseauImporte, listPei, listPeiProjet, useReseauImporteWithCourant); couvertureHydrauliqueRepository.executeParcoursCouverture( - reseauImporte, idEtude, distances, listPei, listPeiProjet, profondeurCouverture); + reseauImporte, + idEtude, + distances, + listPei, + listPeiProjet, + profondeurCouverture, + useReseauImporteWithCourant); couvertureHydrauliqueRepository.executeCouvertureHydrauliqueZonage( idEtude, distances, listPei, listPeiProjet, profondeurCouverture); diff --git a/remocra/src/main/java/fr/sdis83/remocra/web/CouvertureHydrauliqueController.java b/remocra/src/main/java/fr/sdis83/remocra/web/CouvertureHydrauliqueController.java index e92a658a0..6380604c1 100644 --- a/remocra/src/main/java/fr/sdis83/remocra/web/CouvertureHydrauliqueController.java +++ b/remocra/src/main/java/fr/sdis83/remocra/web/CouvertureHydrauliqueController.java @@ -37,9 +37,15 @@ public ResponseEntity calcul(MultipartHttpServletRequest request) { String hydrantsProjet = request.getParameter("hydrantsProjet"); Long etude = Long.valueOf(request.getParameter("etude")); Boolean useReseauImporte = Boolean.valueOf(request.getParameter("reseauImporte")); + Boolean useReseauImporteWithReseauCourant = + Boolean.valueOf(request.getParameter("reseauImporteWithCourant")); couvertureHydrauliqueUseCase.calcul( - hydrantsExistants, hydrantsProjet, etude, useReseauImporte); + hydrantsExistants, + hydrantsProjet, + etude, + useReseauImporte, + useReseauImporteWithReseauCourant); return new ResponseEntity<>("La couverture hydraulique a bien été tracée", HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); diff --git a/server/sdis-remocra/home/postgres/remocra_db/patches/194/194.sql b/server/sdis-remocra/home/postgres/remocra_db/patches/194/194.sql new file mode 100644 index 000000000..65cfb54b9 --- /dev/null +++ b/server/sdis-remocra/home/postgres/remocra_db/patches/194/194.sql @@ -0,0 +1,418 @@ +begin; +set statement_timeout = 0; +set client_encoding = 'UTF8'; +set standard_conforming_strings = off; +set check_function_bodies = false; +set client_min_messages = warning; +set escape_string_warning = off; +set search_path = remocra, pdi, public, pg_catalog; +-------------------------------------------------- +-- Versionnement du patch et vérification +-- +create or replace function versionnement_dffd4df4df() returns void language plpgsql AS $body$ +declare + numero_patch int; + description_patch varchar; +begin + -- Métadonnées du patch + numero_patch := 194; + description_patch := 'Ajoute un paramètre dans les fonctions de la couverture hydraulique pour prendre en compte le réseau importé ET le réseau courant.'; + + -- Vérification + if (select numero_patch-1 != (select max(numero) from remocra.suivi_patches)) then + raise exception 'Le numéro de patch requis n''est pas le bon. Dernier appliqué : %, en cours : %', (select max(numero) from remocra.suivi_patches), numero_patch; end if; + -- Suivi + insert into remocra.suivi_patches(numero, description) values(numero_patch, description_patch); +end $body$; +select versionnement_dffd4df4df(); +drop function versionnement_dffd4df4df(); +-------------------------------------------------- +-- Contenu réel du patch début +DROP FUNCTION couverture_hydraulique.inserer_jonction_pei(integer, integer, integer); +CREATE OR REPLACE FUNCTION couverture_hydraulique.inserer_jonction_pei(pei_id integer, distance_max_au_reseau integer, idetude integer, useReseauImporteWithCourant boolean) + RETURNS integer + LANGUAGE plpgsql +AS $function$ + DECLARE + jonction record; + voie1 record; + voie2 record; + voie2Id integer; + voieJonctionId integer; + sommetJonction integer; + sommetPei integer; + + BEGIN + --Récupère le troncon le + proche du PEI et calcule de point de jonction sur le troncon + SELECT INTO jonction + ST_ClosestPoint(t.geometrie, p.geometrie) AS jonction_geometrie, + ST_LineLocatePoint(t.geometrie, p.geometrie) AS jonction_fraction, + p.id AS pei_id, + p.geometrie AS pei_geometrie, + t.id AS troncon_id, + t.geometrie AS troncon_geometrie + FROM + (SELECT * FROM couverture_hydraulique.pei WHERE id = pei_id) AS p + CROSS JOIN LATERAL + (SELECT DISTINCT ON (p.id) + t.id, + t.geometrie, + ST_Distance(t.geometrie, p.geometrie) AS distance + FROM + couverture_hydraulique.reseau t + WHERE + ST_Dwithin(p.geometrie,t.geometrie,distance_max_au_reseau) + AND CASE + WHEN useReseauImporteWithCourant THEN (t.etude IS NOT DISTINCT FROM idEtude OR t.etude IS NULL) + ELSE t.etude IS NOT DISTINCT FROM idEtude + END + AND t.pei_troncon IS NULL + ORDER BY + p.id, + distance ASC + ) AS t; + -- Si le point de jonction n'est pas null et qu'il ne corresponds pas à une extremité existante du tronçon, + -- procède à la découpe du troncon initial en 2. + IF jonction.jonction_geometrie IS NOT NULL AND jonction.jonction_fraction >= 0.00001 AND jonction.jonction_fraction < 0.99999 THEN + --Mise à jour de géométrie du troncon à découper + UPDATE couverture_hydraulique.reseau t SET + geometrie = ST_LineSubstring(t.geometrie,0,jonction.jonction_fraction) + WHERE + id = jonction.troncon_id; + + -- Insertion du complément + SELECT * INTO voie1 FROM couverture_hydraulique.reseau WHERE id = jonction.troncon_id; + INSERT INTO couverture_hydraulique.reseau ( + geometrie, etude, traversable, sens_unique, niveau + ) VALUES ( + ST_LineSubstring(jonction.troncon_geometrie,jonction.jonction_fraction,1), + idEtude, + voie1.traversable, + voie1.sens_unique, + voie1.niveau + ) RETURNING id INTO voie2Id; + + -- Insertion de la jonction entre le PEI et le réseau + INSERT INTO couverture_hydraulique.reseau ( + geometrie, + pei_troncon, + etude + ) VALUES ( + St_MakeLine(jonction.pei_geometrie, jonction.jonction_geometrie), + pei_id, + idEtude + ) RETURNING id INTO voieJonctionId; + + -- Création du sommet entre les 3 voies et du sommet sur le PEI, modification des sommets source/destination en adéquation + SELECT * into voie1 from couverture_hydraulique.reseau where id = jonction.troncon_id; + SELECT * into voie2 from couverture_hydraulique.reseau where id = voie2Id; + INSERT INTO couverture_hydraulique.sommet(geometrie) VALUES(jonction.jonction_geometrie) RETURNING id INTO sommetJonction; + INSERT INTO couverture_hydraulique.sommet(geometrie) VALUES(jonction.pei_geometrie) RETURNING id INTO sommetPei; + + UPDATE couverture_hydraulique.reseau SET destination = voie1.destination WHERE id = voie2.id; + UPDATE couverture_hydraulique.reseau SET destination = sommetJonction WHERE id = voie1.id OR id = voieJonctionId; + UPDATE couverture_hydraulique.reseau SET source = sommetJonction WHERE id = voie2.id; + UPDATE couverture_hydraulique.reseau SET source = sommetPei WHERE id = voieJonctionId; + + ELSIF jonction.jonction_geometrie IS NOT NULL AND (jonction.jonction_fraction < 0.00001 OR jonction.jonction_fraction = 1) THEN + SELECT id INTO sommetJonction FROM couverture_hydraulique.sommet order by st_distance(geometrie, jonction.jonction_geometrie) limit 1; + INSERT INTO couverture_hydraulique.sommet(geometrie) VALUES(jonction.pei_geometrie) RETURNING id INTO sommetPei; + INSERT INTO couverture_hydraulique.reseau ( + geometrie, + pei_troncon, + etude, + source, + destination + ) VALUES ( + St_MakeLine(jonction.pei_geometrie, jonction.jonction_geometrie), + pei_id, + idEtude, + sommetPei, + sommetJonction + ); + END IF; + + RETURN 1; + END; +$function$ +; + + +DROP FUNCTION couverture_hydraulique.parcours_couverture_hydraulique(integer, integer, integer, integer[], integer); +CREATE OR REPLACE FUNCTION couverture_hydraulique.parcours_couverture_hydraulique(depart integer, idetude integer, idreseauimporte integer, isodistances integer[], profondeurcouverture integer, usereseauimportewithcourant boolean) + RETURNS integer + LANGUAGE plpgsql +AS $function$ +DECLARE + tabDistances int[]; + dist integer; + noeudsAVisiter integer[]; + noeudsVisites integer[]; + noeudCourant integer; + debutChemin boolean; + voisinRecord record; + voisinRecordFromVoieLaterale record; + premiereVoieNonTraversableRencontree record; + courantRecord record; + t record; + distanceParcourue double precision; + voieCourante integer; + bufferSizeRestreint integer; + voieGauche record; + voieDroite record; + buffer geometry; + blade geometry; + bladeSommets geometry; + splitResult geometry; + bufferSommets geometry; + bufferEndPoint geometry; + bufferSide character varying; + bufferEndCap character varying; + recordCouverture record; +BEGIN + TRUNCATE ONLY couverture_hydraulique.temp_distances; + bufferSizeRestreint = 5; -- Buffer pour les voies restreintes (pont, tunnels, etc) via champ niveau != 0 + + -- On trie les distances par ordre croissant et on retranche la taille du buffer + SELECT ARRAY(SELECT unnest-profondeurcouverture FROM unnest(isodistances) ORDER BY unnest) INTO tabDistances; + + FOREACH dist in ARRAY tabDistances LOOP + noeudsAVisiter = array[]::integer[]; + noeudsVisites = array[]::integer[]; + debutChemin = true; + distanceParcourue = 0; + -- Premier parcourt depuis ce PEI: on récupère le premier noeud à visite + IF tabDistances[1] = dist THEN + DELETE FROM couverture_hydraulique.temp_distances where start = depart; + SELECT source into noeudCourant from couverture_hydraulique.reseau where pei_troncon = depart; + noeudsAVisiter = array_append(noeudsAVisiter, noeudCourant); + -- Parcours suivants: on reprend une partie des données (le parcours N contient le parcours N-1) + ELSE + noeudsAVisiter = (SELECT ARRAY( + SELECT DISTINCT sommet FROM couverture_hydraulique.temp_distances WHERE voie IN ( + SELECT DISTINCT voieprecedente + FROM couverture_hydraulique.temp_distances + WHERE distance = tabDistances[(array_position(tabDistances, dist)-1)] + ) + )::int[]); + DELETE FROM couverture_hydraulique.temp_distances + where start = depart + AND distance = tabDistances[(array_position(tabDistances, dist)-1)]; + END IF; + -- Pour tous les noeuds à visiter + WHILE cardinality(noeudsAVisiter) > 0 LOOP + SELECT noeudsAVisiter[1] into noeudCourant; + noeudsVisites = array_append(noeudsVisites, noeudCourant); + SELECT * INTO courantRecord FROM couverture_hydraulique.temp_distances + WHERE start = depart AND sommet = noeudCourant + ORDER BY distance LIMIT 1; + -- Si c'est la voie de départ, il n'y a aucune occurence dans la table temp_distances. On récupère néanmoins son ID afin de pouvoir déterminer les voies partant à sa gauche et à sa droite + IF courantRecord IS NULL THEN + SELECT id INTO voieCourante FROM couverture_hydraulique.reseau WHERE pei_troncon = depart; + END IF; + + PERFORM couverture_hydraulique.voiesLaterales(COALESCE(courantRecord.voie, voieCourante), noeudCourant, idReseauImporte); + SELECT * FROM couverture_hydraulique.voiesLaterales WHERE gauche INTO voieGauche; + SELECT * FROM couverture_hydraulique.voiesLaterales WHERE droite INTO voieDroite; + + -- Pour tous les noeuds voisins + FOR voisinRecord IN (SELECT * FROM ( + (SELECT id, destination, source, ST_LENGTH(geometrie) as distance, geometrie, pei_troncon, traversable, niveau + FROM couverture_hydraulique.reseau + WHERE source = noeudCourant + AND (id IN ((SELECT voie FROM couverture_hydraulique.voieslaterales)) OR (voieGauche.voie IS NULL AND voieDroite.voie IS NULL)) + AND CASE + WHEN useReseauImporteWithCourant THEN (etude IS NOT DISTINCT FROM idReseauImporte OR etude IS NULL) + ELSE etude IS NOT DISTINCT FROM idEtude + END) + UNION + (SELECT id, source as destination, source as source, ST_LENGTH(geometrie) as distance, ST_REVERSE(geometrie), pei_troncon, traversable, niveau + FROM couverture_hydraulique.reseau + WHERE destination = noeudCourant + AND (id IN ((SELECT voie FROM couverture_hydraulique.voieslaterales)) OR (voieGauche.voie IS NULL AND voieDroite.voie IS NULL)) + AND CASE + WHEN useReseauImporteWithCourant THEN (etude IS NOT DISTINCT FROM idReseauImporte OR etude IS NULL) + ELSE etude IS NOT DISTINCT FROM idEtude + END) + ) as R ) LOOP + + -- On prend les voies étant un troncon pei seulement lors du premier parcours. Lors des suivants, ces troncons sont ignorés + CONTINUE WHEN (voisinRecord.pei_troncon > 0 AND debutChemin = FALSE) OR voisinRecord.id = courantRecord.voie; + + SELECT * INTO voisinRecordFromVoieLaterale FROM couverture_hydraulique.voiesLaterales + WHERE voie = voisinRecord.id; + + -- Si c'est une voie non accessible (carrefour où l'on doit passer auparavant par des voies gauche et droite non traversables), on stoppe + CONTINUE WHEN (voisinRecordFromVoieLaterale.accessible IS NOT NULL AND voisinRecordFromVoieLaterale.accessible = FALSE); + + IF(voieGauche IS NOT NULL AND voieDroite IS NOT NULL AND voieGauche.voie != voieDroite.voie) THEN + -- Si c'est une voie à gauche, que la voie courante est non traversable et que l'on trace le buffer sur notre droite et que ce + -- n'est pas la première voie non traversable rencontrée sur notre droite + SELECT * INTO premiereVoieNonTraversableRencontree + FROM couverture_hydraulique.voieslaterales + WHERE traversable = false + ORDER BY ANGLE DESC LIMIT 1; + CONTINUE WHEN (voisinRecordFromVoieLaterale.gauche = TRUE + and courantRecord.traversable = FALSE + AND courantRecord.side = 'right' + AND premiereVoieNonTraversableRencontree.voie != voisinRecordFromVoieLaterale.voie); + + -- Si c'est une voie à droite, que la voie courante est non traversable, que l'on trace le buffer sur notre gauche et que ce + -- n'est pas la première voie non traversable rencontrée sur notre gauche + SELECT * INTO premiereVoieNonTraversableRencontree + FROM couverture_hydraulique.voieslaterales + WHERE traversable = FALSE + ORDER BY ANGLE LIMIT 1; + CONTINUE WHEN (voisinRecordFromVoieLaterale.droite = TRUE + and courantRecord.traversable = FALSE + AND courantRecord.side = 'left' + AND premiereVoieNonTraversableRencontree.voie != voisinRecordFromVoieLaterale.voie); + + END IF; + + -- Si la voie est trop longue, on n'en parcourt qu'une partie + IF voisinRecord.distance + COALESCE(courantRecord.distance, 0) > dist AND COALESCE(courantRecord.distance, 0) < dist THEN + distanceParcourue = COALESCE(courantRecord.distance, 0) + voisinRecord.distance; + Select ST_LineSubstring(voisinRecord.geometrie, 0, + (CASE + WHEN distanceParcourue <= dist THEN 1 + ELSE (1 -((distanceParcourue - dist)/voisinRecord.distance)) + END) + )::geometry(LineString,2154) INTO voisinRecord.geometrie; + SELECT ST_PointN( + voisinRecord.geometrie, + generate_series(2, ST_NPoints(voisinRecord.geometrie)) + ) INTO bufferEndPoint; + distanceParcourue = dist; + ELSE + distanceParcourue = COALESCE(courantRecord.distance, 0) + voisinRecord.distance; + SELECT geometrie INTO bufferEndPoint FROM couverture_hydraulique.sommet + WHERE id = ( + CASE + WHEN voisinRecord.source != noeudCourant THEN voisinRecord.source + ELSE voisinRecord.destination + END) + AND debutChemin = false; + END IF; + + -- Le chemin pour aller au noeud n'existe pas en mémoire ou il en existe déjà un plus long => on remplace par le chemin courant + SELECT * INTO t FROM couverture_hydraulique.temp_distances + WHERE start = depart AND sommet = voisinRecord.destination and voie = voisinRecord.id; + + IF t IS NULL AND distanceParcourue <= dist THEN + /** =============================================== Tracé du buffer de la voie ==================================================== **/ + -- On détermine de quel côté tracer le buffer + IF courantRecord.traversable = false and voisinRecord.traversable = false then + bufferSide = courantRecord.side; + bufferEndCap = 'round'; + elsif voisinRecord.traversable THEN + bufferSide = 'both'; + bufferEndCap = 'round'; + ELSIF voieGauche.voie = voieDroite.voie THEN + bufferSide = courantRecord.side; + bufferEndCap = 'round'; + ELSIF voisinRecord.id = voieGauche.voie THEN + --bufferSide = 'left'; + bufferSide = CASE + WHEN courantRecord.side = 'both' THEN 'left' + ELSE courantRecord.side + END; + bufferEndCap = 'flat'; + ELSIF voisinRecord.id = voieDroite.voie THEN + --bufferSide = 'right'; + bufferSide = CASE + WHEN courantRecord.side = 'both' THEN 'right' + ELSE courantRecord.side + END; + bufferEndCap = 'flat'; + END IF; + + buffer = ST_BUFFER(voisinRecord.geometrie, ( + CASE WHEN voisinRecord.niveau != 0 THEN bufferSizeRestreint + ELSE profondeurcouverture END + ), CONCAT('side=', bufferSide, ' endcap=', bufferEndCap)); + + -- Si le buffer traverse une voie non traversable, on retire la partie en trop + SELECT ST_UNION(geometrie) INTO blade + FROM (SELECT geometrie FROM couverture_hydraulique.reseau + WHERE pei_troncon IS NULL AND NOT traversable + AND niveau = 0 AND id != voisinRecord.id AND ST_INTERSECTS(buffer, geometrie) + AND etude IS NOT DISTINCT FROM idReseauImporte) AS R; + + IF blade IS NOT NULL THEN + splitResult = ST_SPLIT(buffer, blade); + IF ST_NUMGEOMETRIES(splitResult) > 1 THEN + SELECT geom INTO buffer FROM ( + SELECT (st_dump(st_split(buffer, blade))).geom + ) AS R ORDER BY st_distance(ST_LineInterpolatePoint(voisinRecord.geometrie, 0.001), geom) LIMIT 1; + END IF; + END IF; + /** =============================================================================================================================== **/ + + /** ================================== Ajout des buffer de destination des voies ===================================== **/ + IF bufferSide != 'both' THEN + bufferSommets = ST_BUFFER(bufferEndPoint,profondeurcouverture); + SELECT ST_UNION(geometrie) INTO bladeSommets + FROM (SELECT geometrie FROM couverture_hydraulique.reseau + WHERE ST_INTERSECTS(geometrie, bufferSommets) AND pei_troncon IS NULL + AND NOT traversable AND niveau = 0) AS R; + + IF bladeSommets IS NOT NULL THEN + SELECT ST_UNION(buffer, geom) INTO buffer FROM ( + SELECT (st_dump(st_split(bufferSommets, bladeSommets))).geom + ) AS R ORDER BY ST_AREA(ST_INTERSECTION(geom, buffer))/ST_AREA(geom) DESC LIMIT 1; + END IF; + END IF; + /** =============================================================================================================================== **/ + DELETE FROM couverture_hydraulique.temp_distances + WHERE start = depart AND voie = voisinRecord.id AND sommet = voisinRecord.destination; + + -- Si le buffer est un MultiPolygon, on le cast en Polygon + IF ST_GeometryType(buffer) = 'ST_MultiPolygon' THEN + SELECT (ST_Dump(buffer)).geom INTO buffer; + END IF; + INSERT INTO couverture_hydraulique.temp_distances (start, sommet, voie, distance, geometrie, voiePrecedente, traversable, side) + SELECT depart, voisinRecord.destination, voisinRecord.id, distanceParcourue, buffer, + courantRecord.voie, voisinRecord.traversable, bufferSide; + END IF; + -- Si coût inférieur à la limite de recherche et le noeud n'a jamais été visité + IF NOT noeudsVisites @> ARRAY[voisinRecord.destination] AND distanceParcourue < dist THEN + noeudsAVisiter = array_append(noeudsAVisiter, voisinRecord.destination); + END IF; + debutChemin = FALSE; + END LOOP; -- Fin parcourt des voies voisines + + noeudsAVisiter = array_remove(noeudsAVisiter, noeudCourant); + + END LOOP; -- Fin tant que des sommets restent à visiter + + -- Récupération de la géométrie de la couverture hydraulique + DELETE FROM couverture_hydraulique.couverture_hydraulique_pei WHERE distance = dist AND pei = depart; + SELECT dist, depart, idEtude, ST_Union(geometrie) as geometrie INTO recordCouverture + FROM couverture_hydraulique.temp_distances WHERE start = depart; + + -- Si MultiPolygon, on cherche à récupérer un Polygon + IF ST_GeometryType(recordCouverture.geometrie) = 'ST_MultiPolygon' THEN + recordCouverture.geometrie = ST_BUFFER(ST_BUFFER(recordCouverture.geometrie, 0.001), -0,001); + END IF; + + -- Si la condition n'est pas validée à ce stade, l'erreur provient très probablement du jeu de données + IF ST_GeometryType(recordCouverture.geometrie) = 'ST_Polygon' THEN + INSERT INTO couverture_hydraulique.couverture_hydraulique_pei (distance, pei, etude, geometrie) + VALUES(recordCouverture.dist, recordCouverture.depart, recordCouverture.idEtude, recordCouverture.geometrie); + END IF; + END LOOP; -- Fin for pour chaque distance + + DELETE FROM couverture_hydraulique.voiesLaterales; + DELETE FROM couverture_hydraulique.temp_distances; + + RETURN 1; +END; +$function$ +; + + + +-- Contenu réel du patch fin +-------------------------------------------------- +COMMIT; \ No newline at end of file