diff --git a/CHANGELOG.md b/CHANGELOG.md
index 78c916125b298bd5fb7552a0180d03335479d05a..1ab7f4a4808c25ba24328419c91ed4259ac86826 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,27 +1,43 @@
 # Historique des versions
 
-### 4.16.0 (en cours)
+### 4.16.0
 
 #### Nouvelles fonctionnalités
 
 * URL de routeur "/loadsession" pour charger un exemple ([nghyd#476](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/476))
 * Deploy devel branch on cassiopee-dev.g-eau.fr ([nghyd#564](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/564))
+* PAB : ajout de la charge et l'ennoiement dans le tableau de résultat et l'export ([jalhyd#324](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/324), [nghyd#518](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/518))
+* Courbe de remous (et bief) : remontée d'une erreur quand le pas de discrétisation est supérieur à la longueur du bief ([jalhyd#316](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/316), [nghyd#565](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/565))
+* Section paramétrée : profil de section : option axes orthonormés ([nghyd#497](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/497))
 
 #### Changements
 
 * Mise à jour vers Angular 14 ([nghyd#500](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/500))
 * CI : MAJ de l'image Docker vers Debian Bullseye
-* Angular : compiler avec Ivy ([nghyd#369](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/369))
+* Angular : compilation avec Ivy ([nghyd#369](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/369))
 * Déplacer le répertoire Jalhyd dans celui de Nghyd ([nghyd#558](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/558))
+* Ouvrages: modification des types d'ouvrages (ajout de seuil/orifice rectangulaire, vanne rectangulaire renommée en vanne de fond rectangulaire) ([jalhyd#326](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/326), [nghyd#511](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/511))
+* Documentation : corrections diverses ([nghyd#559](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/559))
+* Déménagement de l'intégration continue sur les serveurs gitlab à Lyon ([nghyd#557](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/557))
+* Mise à jour de Chartjs ([nghyd#554](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/554))
+* Documentation : MacroRugo : ajout d'un schéma rugosité de fond ([nghyd#524](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/524))
+* Prébarrages : regroupement de la saisie des bassins ([nghyd#522](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/522))
+* Documentation : lois d'ouvrages : définition seuil mince/épais ([nghyd#514](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/514))
+* Documentation : ajout d'un tableau synthétiques des lois d'ouvrages ([nghyd#513](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/513))
+* MAJ de l'image Docker à la version Debian Bullseye (compatibilité TLS) ([cassiopee2-integration#10](https://gitlab.irstea.fr/cassiopee/cassiopee2-integration/-/issues/10))
+* MAJ vers PrimeNG 10 ([nghyd#481](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/481))
+* Documentation : MAJ de la documentation des grilles avec les données de Lemkecher et al. (2020) ([nghyd#438](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/438))
 
 #### Correction de bogues
 
 * Les caractères UTF8 ne sont pas imprimés dans la doc PDF ([nghyd#556](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/556))
 * PréBarrages: La sélection de l'amont ou l'aval n'est pas visible au premier clic ([nghyd#560](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/560))
-* Courbe de remous (et bief): remonter une erreur quand le pas de discrétisation est supérieur la longueur du bief ([nghyd#565](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/565))
 * Solveur: le paramètre recherché n'est pas conservé ([nghyd#555](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/555))
 * PAB: Bugs de format du tableau NgPrime ([nghyd#562](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/562))
-* Section paramétrée: crash de l'appli sur variation de paramètre ([nghyd#561](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/561))
+* Section paramétrée: crash de l'appli sur variation de paramètre ([jalhyd#319](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/319), [nghyd#561](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/561))
+* Module avec une section : le mode champs vide ne fonctionne pas ([jalhyd#327](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/327), [nghyd#569](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/569))
+* Déplacement du paramètre calculé lors de la duplication d'un Nub ([jalhyd#322](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/322), [nghyd#567](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/567))
+* Lois d'ouvrages : mauvaise gestion du paramètre calculé sur suppression d'ouvrage ([jalhyd#321](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/321), [nghyd#566](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/566))
 
 ### 4.15.1 - 2022-07-04
 
diff --git a/docs/en/calculators/pam/macrorugo.md b/docs/en/calculators/pam/macrorugo.md
index 09b471f1bd41e84f13579299750cae2efebeb671..0efc4e042e8ef16fd8af6bb65d5c432848fa673d 100644
--- a/docs/en/calculators/pam/macrorugo.md
+++ b/docs/en/calculators/pam/macrorugo.md
@@ -25,3 +25,8 @@ It requires the following values to be entered:
 - The width of the blocks \(D\) facing the flow (m);
 - The useful height of the blocks \(k\) (m);
 - The drag coefficient of a single block (1 for round, 2 for square).
+
+<div style="position: relative"><a id="rugosite-de-fond" style="position: absolute; top: -60px;"></a></div>
+# Bed roughness
+
+![](schema_rugosite_fond.png)
diff --git a/docs/en/calculators/pam/schema_rugosite_fond.png b/docs/en/calculators/pam/schema_rugosite_fond.png
new file mode 100644
index 0000000000000000000000000000000000000000..57969041c6d9b2d45573cd0e5a1a0bbd78d9b46a
Binary files /dev/null and b/docs/en/calculators/pam/schema_rugosite_fond.png differ
diff --git a/docs/fr/calculators/pam/macrorugo.md b/docs/fr/calculators/pam/macrorugo.md
index 646df7cff0f188f39ed5c5937258f71f7987acb7..83395baef05257c0711ed32229f849e1d8f967f9 100644
--- a/docs/fr/calculators/pam/macrorugo.md
+++ b/docs/fr/calculators/pam/macrorugo.md
@@ -26,3 +26,6 @@ Il nécessite d'entrer les valeurs suivantes&nbsp;:
 - La hauteur utile des blocs \(k\) (m)&nbsp;;
 - Le coefficient de trainée d'un bloc (1 pour rond, 2 pour carré).
 
+# Rugosité de fond
+
+![](schema_rugosite_fond.png)
diff --git a/docs/fr/calculators/pam/schema_rugosite_fond.png b/docs/fr/calculators/pam/schema_rugosite_fond.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee526a871fe372484dc25a1cd18463a0de1d5c97
Binary files /dev/null and b/docs/fr/calculators/pam/schema_rugosite_fond.png differ
diff --git a/jalhyd_branch b/jalhyd_branch
index 5327f921cccee39cb4e77fc0882bfd05e703507a..d64531f1305e091791eac674c3a36d86b9e17ddd 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-327-module-avec-une-section-le-mode-champs-vide-ne-fonctionne-pas
+devel
diff --git a/src/app/calculators/macrorugo/config.json b/src/app/calculators/macrorugo/config.json
index 6cbce4d4541d9cb123908d3026a6026c0a061954..6b9ee9a8f8c0303b91de90757d2ee8b6cc57c183 100644
--- a/src/app/calculators/macrorugo/config.json
+++ b/src/app/calculators/macrorugo/config.json
@@ -5,7 +5,10 @@
         "fields": [
             "ZF1",
             "L",
-            "Ks"
+            {
+                "id": "Ks",
+                "help": "pam/macrorugo.html#rugosite-de-fond"
+            }
         ]
     },
     {
@@ -41,4 +44,4 @@
         "type": "options",
         "help": "pam/macrorugo.html"
     }
-]
\ No newline at end of file
+]
diff --git a/src/app/calculators/macrorugocompound/config.json b/src/app/calculators/macrorugocompound/config.json
index 496a352629be9d42c5f98a37d5052df441743b16..8df7adca30b829076b1b3929bd2548686112fde9 100644
--- a/src/app/calculators/macrorugocompound/config.json
+++ b/src/app/calculators/macrorugocompound/config.json
@@ -15,7 +15,10 @@
                 "id": "If",
                 "help": "hsl/pente.html"
             },
-            "Ks",
+            {
+                "id": "Ks",
+                "help": "pam/macrorugo.html#rugosite-de-fond"
+            },
             {
                 "id": "C",
                 "help": "pam/concentration.html"
@@ -43,8 +46,14 @@
                 "type": "select",
                 "property": "inclinedApron"
             },
-            "ZRR",
-            "ZRL",
+            {
+                "id": "ZRR",
+                "help": "pam/macrorugo.html#rugosite-de-fond"
+            },
+            {
+                "id": "ZRL",
+                "help": "pam/macrorugo.html#rugosite-de-fond"
+            },
             "BR"
         ]
     },
@@ -53,7 +62,10 @@
         "type": "fieldset_template",
         "calcType": "MacroRugo",
         "fields": [
-            "ZF1",
+            {
+                "id": "ZF1",
+                "help": "pam/macrorugo.html#rugosite-de-fond"
+            },
             "B"
         ]
     },
@@ -69,4 +81,4 @@
         "selectIds": [ "select_passtype" ],
         "help": "pam/macrorugo_complexe.html"
     }
-]
\ No newline at end of file
+]
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
index 88a38d36647ccd4aee85a011001154ac7898e943..1f5ea4b720bfcb4bbf0ccbd85f42bde4dc582540 100644
--- a/src/app/components/remous-results/remous-results.component.ts
+++ b/src/app/components/remous-results/remous-results.component.ts
@@ -374,7 +374,7 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
             } else {
                 lineExtra.data = {
                     label: this.extraParamLabel,
-                    tension: 0, fill: false, spanGaps: true, borderColor: "#C17AF0", pointRadius: 4, showLine: "true"
+                    tension: 0, fill: false, spanGaps: true, borderColor: "#C17AF0", pointBackgroundColor: "#C17AF0", pointRadius: 4, backgroundColor: "#C17AF0", showLine: "true"
                 };
             }
         }
@@ -452,7 +452,7 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                 tooltip: {
                     callbacks: {
                         label: function (tooltipItem) {
-                            return fv(Number(tooltipItem.formattedValue));
+                            return fv(tooltipItem.dataset.data[tooltipItem.dataIndex].y);
                         }
                     }
                 },
@@ -496,8 +496,10 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                         },
                         ticks: {
                             precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION,
-                            callback: function (value, index, values) {
-                                return fv(Number(value));
+                            callback: (value, index, values) => {
+                                // pour une raison mystérieuse, values ne contient pas les x fournis mais des valeurs générées,
+                                // et donc value est inutilisable
+                                return fv(gr2.data.datasets[0].data[index].x);
                             }
                         },
                     }
@@ -510,7 +512,10 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                     tooltip: {
                         callbacks: {
                             label: function (tooltipItem) {
-                                return fv(Number(tooltipItem.formattedValue));
+                                return fv(tooltipItem.dataset.data[tooltipItem.dataIndex].y);
+                            },
+                            title: () => {  // pour empêcher le tooltip de contenir l'abscisse du point
+                                return undefined; // pq a t-on besoin de ce callback dans ce graphe et pas dans l'autre ? mystère aussi...
                             }
                         }
                     },
diff --git a/src/app/components/section-canvas/section-canvas.component.html b/src/app/components/section-canvas/section-canvas.component.html
index da242b966d3d4eb18ed9873ad32e8779fec1ce6b..fc687f76cb6b9420bdf574549d9df16370711eee 100644
--- a/src/app/components/section-canvas/section-canvas.component.html
+++ b/src/app/components/section-canvas/section-canvas.component.html
@@ -1,2 +1,7 @@
-<canvas #canvas [attr.width]="width" [attr.height]="height">
-</canvas>
+<div fxLayout="column" fxLayoutAlign="center center">
+    <canvas #canvas [attr.width]="width" [attr.height]="height">
+    </canvas>
+    <mat-checkbox [ngModel]="useRealAspectRatio" (ngModelChange)="setUseRealAspectRatio($event)">
+        {{ uitextUseRealRatio }}
+    </mat-checkbox>
+</div>
\ No newline at end of file
diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index 41364eac3afb02d9d0c18364d1494b1460973bdb..cc5f23320ca1bbd9e200af565867e1c26035e866 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -1,4 +1,5 @@
 import { Component, ViewChild, Input, OnChanges, AfterViewInit, ElementRef } from "@angular/core";
+import { I18nService } from "app/services/internationalisation.service";
 
 import {
     acSection, cSnTrapez, ParamsSectionTrapez, cSnRectang, ParamsSectionRectang, cSnCirc,
@@ -26,32 +27,77 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         "Y": { r: 50, g: 50, b: 50 }
     };
 
-    /** marges gauche/droite pour le texte (pixels) */
-    private _textMargin = 90;
+    /*
+     * notes :
+     * - l'origine des coordonnées en m est par ex pour la section rectangulaire le coin en bas (radier) à gauche de la section
+     * - canal : partie physique, sans les niveaux d'eau
+     * - section : canal + niveaux d'eau
+     * - rendu : section + texte + pointillés en haut
+     * - W : dimension horizontale, H : dimension verticale
+     * _ _m : valeur en mètres, _pix : valeur en pixels
+     */
+
+    /** largeur gauche/droite du texte (pixels) */
+    private readonly _textWidth = 110;
 
     /** marge basse (pixels) */
-    private _bottomMargin = 5;
+    private readonly _bottomMargin = 5;
+
+    /** marge haute pour les pointillés (pixels) */
+    private readonly _topDashMargin = 30;
+
+    /** largeur des repères des niveaux sur le bord de la section (pixels) */
+    private readonly _levelMark = 5;
 
     /** facteurs d'échelle (coordonnées en m <-> coordonnées en pixels) */
     private _scaleX: number;
     private _scaleY: number;
 
+    /** origine (pixels) */
+    private _origX: number;
+    private _origY: number;
+
     private _section: acSection;
 
     private _result: Result;
 
+    /**
+     * paramètre de taille du canvas en entrée (pixels)
+     */
     private _size: number;
 
+    /**
+     * taille horizontale de la section (m)
+     */
+    private _Wsect_m: number;
+
+    /**
+     * taille verticale de la section (m)
+     */
+    private _Hsect_m: number;
+
+    /**
+     * taille horizontale de la section (pixels)
+     */
+    private _Wsect_pix: number;
+
+    /**
+     * taille verticale de la section (pixels)
+     */
+    private _Hsect_pix: number;
+
     // tirants
     private _levels: Object[] = [];
 
+    constructor(private intlService: I18nService) {
+        super();
+    }
+
     public get width(): number {
-        // return this._calcCanvas.nativeElement.width;
         return this._size;
     }
 
     public get height(): number {
-        // return this._calcCanvas.nativeElement.height;
         return this._size;
     }
 
@@ -75,8 +121,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._size = s;
     }
 
+    // respect du rapport abscisses/ordonnées
+    private _useRealAspectRatio: boolean = false;
+
     // redessine le canvas chaque fois qu'une entrée change
     public ngOnChanges() {
+        this.computeSectionWidth();
+        this.computeSectionHeight();
+        this.computeTransform();
         setTimeout(() => {
             this.draw();
         }, 10);
@@ -84,18 +136,126 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
 
     public ngAfterViewInit() { // wait for the view to init before using the element
         this._context2d = this._calcCanvas.nativeElement.getContext("2d");
+    }
+
+    /**
+     * calcul des tailles horizontale et verticale de la zone de rendu (pixels)
+     * @returns true si le rendu touche le haut et le bas du canvas
+     */
+    private computeRenderSize(): boolean {
+        let res: boolean;
+        if (this._useRealAspectRatio) {
+            // largeur en pixels pour la représentation de la section
+            const a = this.width - 2 * (this._textWidth + this._levelMark);
+
+            // calcul des rapports largeur/hauteur pour le canvas et la section
+            const rlim = a / this.height;
+            const rsect = this._Wsect_m / this._Hsect_m;
+
+            if (rsect <= rlim) {
+                this._Hsect_pix = this.height - this._bottomMargin - this._topDashMargin;
+                this._Wsect_pix = this._Hsect_pix * rsect;
+                res = true;
+            }
+            else {
+                this._Wsect_pix = a;
+                this._Hsect_pix = this._Wsect_pix / rsect;
+                res = false;
+            }
+
+        } else {
+            this._Wsect_pix = this.width - 2 * (this._textWidth + this._levelMark)
+            this._Hsect_pix = this.height - this._bottomMargin - this._topDashMargin;
+            res = true;
+        }
+
+        return res;
+    }
+
+    /**
+     * calcul du coef pour passer de m -> pixels
+     * et de l'origine du rendu
+     */
+    private computeTransform() {
+        const b = this.computeRenderSize();
+
+        // échelle m -> pix
+        this._scaleX = this._Wsect_pix / this._Wsect_m;
+        this._scaleY = this._Hsect_pix / this._Hsect_m;
+        // origine
+        this._origX = (this._size - this._Wsect_pix) / 2;
+        this._origY = b ? this._bottomMargin : (this._size - this._Hsect_pix) / 2;
+    }
+
+    /**
+     * convertit une abscisse en m en pixels
+     */
+    private Xm2pix(x: number) {
+        return this._origX + x * this._scaleX;
+    }
+
+    /**
+     * convertit une ordonnée en m en pixels
+     */
+    private Ym2pix(y: number) {
+        return this._size - this._origY - y * this._scaleY;
+    }
+
+    public get useRealAspectRatio(): boolean {
+        return this._useRealAspectRatio;
+    }
+
+    public setUseRealAspectRatio(b: boolean) {
+        this._useRealAspectRatio = b;
+        this.computeTransform();
         this.draw();
     }
 
-    public reset() {
+    private setLevels() {
         this._levels = [];
-        this.clear();
+
+        // traduction des symboles des variables calculées
+        const re = this._result.resultElement;
+        if (re !== undefined) {
+            for (const k in re.values) {
+                if (k !== re.vCalcSymbol) {
+                    //const lbl = k.toUpperCase();
+                    const er = re.getValue(k);
+                    // this._resultElement.addExtraResult(lbl, er);
+
+                    if (this.isSectionLevel(k)) {
+                        this.addLevel(er, k + " = " + this.formattedValue(er), SectionCanvasComponent.labelColors[k]);
+                    }
+                }
+            }
+        }
+
+        // ajout du tirant d'eau saisi
+        const valY = this._result.sourceNub.getParameter("Y").singleValue;
+        this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
+
+        this.sortLevels();
     }
 
-    public addLevel(val: number, label: string, rgb: {}) {
+    private addLevel(val: number, label: string, rgb: {}) {
         this._levels.push({ val, label, rgb });
     }
 
+    /**
+     * trie les tirants par niveau d'eau croissant
+     */
+    private sortLevels() {
+        this._levels.sort((a, b) => {
+            if (a["val"] < b["val"]) {
+                return -1;
+            }
+            if (a["val"] > b["val"]) {
+                return 1;
+            }
+            return 0;
+        });
+    }
+
     // max des niveaux à représenter
     private getMaxLevel(): number {
         // max de la cote de berge et des niveaux (qui sont triés)
@@ -111,35 +271,34 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         return false;
     }
 
+    /**
+     * calcul des tailles horizontale et verticale de la section (m)
+     */
+    private computeSectionWidth() {
+        if (this._section instanceof cSnTrapez) {
+            this.computeSectionWidthTrapez();
+        }
+        else if (this._section instanceof cSnRectang) {
+            this.computeSectionWidthRect();
+        }
+        else if (this._section instanceof cSnCirc) {
+            this.computeSectionWidthCirc();
+        }
+        else if (this._section instanceof cSnPuiss) {
+            this.computeSectionWidthPara();
+        }
+        else
+            throw new Error("SectionCanvasComponent.computeSectionWidth() : type de section non pris en charge");
+    }
+
     public draw() {
-        // console.log(">> redrawing at size", this._size);
         if (this._context2d && this._section) {
-            this.reset();
-
-            // traduction des symboles des variables calculées
-            const re = this._result.resultElement;
-            if (re !== undefined) {
-                for (const k in re.values) {
-                    if (k !== re.vCalcSymbol) {
-                        const lbl = k.toUpperCase();
-                        const er = re.getValue(k);
-                        // this._resultElement.addExtraResult(lbl, er);
-
-                        if (this.isSectionLevel(k)) {
-                            this.addLevel(er, k + " = " + this.formattedValue(er), SectionCanvasComponent.labelColors[k]);
-                        }
-                    }
-                }
-            }
-
-            // ajout du tirant d'eau saisi
-            const valY = this._result.sourceNub.getParameter("Y").singleValue;
-            this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
-
-            this.sortLevels();
-            this.drawFrame();
-            const maxWidth = this.drawSection();
-            this.drawLevels(maxWidth);
+            this.clear();
+            setTimeout(() => { // à cause du changement de taille du canvas dans updateCanvasSize()
+                this.drawFrame();
+                this.drawSection();
+                this.drawLevels();
+            }, 10);
         }
     }
 
@@ -149,32 +308,44 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
      * yb : cote de berge
      * maxHeight : valeur maxi des cotes
      */
-    private drawTopDashLines(xmin: number, xmax: number, yb: number, maxHeight: number) {
+    private drawTopDashLines(xmin: number, xmax: number, yb: number) {
         this.setLineWidth(2);
         this.setLineDash([5]);
         this.setStrokeColor(128, 128, 128);
-        this.drawSectionLine(xmin, yb, xmin, maxHeight);
-        this.drawSectionLine(xmax, yb, xmax, maxHeight);
+        const x1 = this.Xm2pix(xmin);
+        const ybp = this.Ym2pix(yb);
+        this.drawLine(x1, ybp, x1, 0);
+        const x2 = this.Xm2pix(xmax);
+        this.drawLine(x2, ybp, x2, 0);
     }
 
-    private drawSectionTrapez(): number {
+    private computeSectionHeight() {
+        this.setLevels();
+
+        // hauteur totale de la section
+        this._Hsect_m = this.getMaxLevel();
+    }
+
+    private computeSectionWidthTrapez() {
         const sect: cSnTrapez = <cSnTrapez>this._section;
         const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms;
 
-        // cote de berge
-        const yb: number = prms.YB.v;
-
         // largeur de la partie pentue
         const lp: number = prms.Fruit.v * prms.YB.v;
 
         // largeur totale de la section
-        const maxWidth: number = lp * 2 + prms.LargeurFond.v;
+        this._Wsect_m = lp * 2 + prms.LargeurFond.v;
+    }
 
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
+    private drawSectionTrapez() {
+        const sect: cSnTrapez = <cSnTrapez>this._section;
+        const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms;
+
+        // cote de berge
+        const yb: number = prms.YB.v;
 
-        this.computeScale(maxWidth, maxHeight);
+        // largeur de la partie pentue
+        const lp: number = prms.Fruit.v * prms.YB.v;
 
         // dessin de la section
 
@@ -182,13 +353,19 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, lp, 0);
         this.drawSectionLine(lp, 0, lp + prms.LargeurFond.v, 0);
-        this.drawSectionLine(lp + prms.LargeurFond.v, 0, maxWidth, yb);
+        this.drawSectionLine(lp + prms.LargeurFond.v, 0, this._Wsect_m, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
+        this.drawTopDashLines(0, this._Wsect_m, yb);
+    }
+
+    private computeSectionWidthRect() {
+        const sect: cSnRectang = <cSnRectang>this._section;
+        const prms: ParamsSectionRectang = <ParamsSectionRectang>sect.prms;
 
-        return maxWidth;
+        // largeur totale de la section
+        this._Wsect_m = prms.LargeurBerge.v;
     }
 
     private drawSectionRect() {
@@ -198,28 +375,39 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // cote de berge
         const yb: number = prms.YB.v;
 
-        // largeur totale de la section
-        const maxWidth: number = prms.LargeurBerge.v;
-
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
-
-        this.computeScale(maxWidth, maxHeight);
 
         // dessin de la section
 
         this.setStrokeColor(0, 0, 0);
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, 0, 0);
-        this.drawSectionLine(0, 0, prms.LargeurBerge.v, 0);
-        this.drawSectionLine(prms.LargeurBerge.v, 0, maxWidth, yb);
+        this.drawSectionLine(0, 0, this._Wsect_m, 0);
+        this.drawSectionLine(this._Wsect_m, 0, this._Wsect_m, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
+        this.drawTopDashLines(0, this._Wsect_m, yb);
+    }
+
+    private computeSectionWidthCirc() {
+        const sect: cSnCirc = <cSnCirc>this._section;
+        const prms: ParamsSectionCirc = <ParamsSectionCirc>sect.prms;
+
+        // cote de berge
+        const yb: number = prms.YB.v;
 
-        return maxWidth;
+        // diamètre, rayon
+        const D: number = prms.D.v;
+        const r: number = D / 2;
+
+        // largeur au miroir
+        const B: Result = sect.CalcSection("B", yb);
+        if (!B.ok) {
+            throw B;
+        }
+
+        // largeur totale de la section
+        this._Wsect_m = yb < r ? B.vCalc : D;
     }
 
     private drawSectionCirc() {
@@ -240,21 +428,12 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
                 throw B;
             }
 
-            // largeur totale de la section
-            const maxWidth: number = yb < r ? B.vCalc : D;
-
-            // hauteur totale de la section
-            let maxHeight: number = this.getMaxLevel();
-            maxHeight *= 1.1;
-
-            this.computeScale(maxWidth, maxHeight);
-
             // dessin de la section
 
             this.setStrokeColor(0, 0, 0);
             this.setLineWidth(5);
 
-            const wx: number = maxWidth / 2;
+            const wx: number = this._Wsect_m / 2;
             const alpha: Result = sect.CalcSection("Alpha", yb);
             if (!alpha.ok) {
                 throw alpha;
@@ -267,33 +446,33 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             // pointillés du haut
 
             const w: number = yb > r ? (D - B.vCalc) / 2 : 0;
-            this.drawTopDashLines(w, maxWidth - w, yb, maxHeight);
-
-            return maxWidth;
+            this.drawTopDashLines(w, this._Wsect_m - w, yb);
         } catch (e) {
             const res: Result = e as Result;
             this.drawText("error : " + res.log.toString(), 0, 0);
         }
     }
 
-    private drawSectionPara() {
+    private computeSectionWidthPara() {
         const sect: cSnPuiss = <cSnPuiss>this._section;
         const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms;
 
-        // cote de berge
-        const yb: number = prms.YB.v;
-
         // largeur au miroir
         const B: number = prms.LargeurBerge.v;
 
         // largeur totale de la section
-        const maxWidth: number = B;
+        this._Wsect_m = B;
+    }
 
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
+    private drawSectionPara() {
+        const sect: cSnPuiss = <cSnPuiss>this._section;
+        const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms;
+
+        // cote de berge
+        const yb: number = prms.YB.v;
 
-        this.computeScale(maxWidth, maxHeight);
+        // largeur au miroir
+        const B: number = prms.LargeurBerge.v;
 
         // contour de la section
 
@@ -312,17 +491,24 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.stroke();
 
         // pointillés du haut
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
-
-        return maxWidth;
+        this.drawTopDashLines(0, this._Wsect_m, yb);
     }
 
     private drawSectionEllipse(x: number, y: number, rX: number, rY: number, rot: number, start: number, end: number) {
         this.drawEllipse(this.Xm2pix(x), this.Ym2pix(y), rX * this._scaleX, rY * this._scaleY, rot, start, end);
     }
 
+    /**
+     * dessine un texte
+     * @param s texte à dessiner
+     * @param x position horizontale (m)
+     * @param y position verticale (m)
+     * @param align alignement "left" ou "right" cf. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
+     */
     private drawText(s: string, x: number, y: number, align?: string) {
-        this.fillText(s, this.Xm2pix(x), this.Ym2pix(y), align);
+        // décalage du texte par rapport au bord gauche/droit de la section
+        const shiftX = align === undefined ? 0 : (align === "left" ? this._levelMark : -this._levelMark);
+        this.fillText(s, this.Xm2pix(x) + shiftX, this.Ym2pix(y), align);
     }
 
     private drawSectionLine(x1: number, y1: number, x2: number, y2: number) {
@@ -333,86 +519,97 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
      * dessin de la section
      * @returns largeur de la section (en m)
      */
-    private drawSection(): number {
+    private drawSection() {
         if (this._section instanceof cSnTrapez) {
-            return this.drawSectionTrapez();
+            this.drawSectionTrapez();
         }
-        if (this._section instanceof cSnRectang) {
-            return this.drawSectionRect();
+        else if (this._section instanceof cSnRectang) {
+            this.drawSectionRect();
         }
-        if (this._section instanceof cSnCirc) {
-            return this.drawSectionCirc();
+        else if (this._section instanceof cSnCirc) {
+            this.drawSectionCirc();
         }
-        if (this._section instanceof cSnPuiss) {
-            return this.drawSectionPara();
+        else if (this._section instanceof cSnPuiss) {
+            this.drawSectionPara();
         }
-        throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
-    }
-
-    private computeScale(maxWidth: number, maxHeight: number) {
-        this._scaleX = (this._size - 2 * this._textMargin) / maxWidth;
-        this._scaleY = (this._size - this._bottomMargin) / maxHeight;
+        else
+            throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
     }
 
     /**
-     * convertit une abscisse en m en pixels
+     * dessin des niveaux en gérant le chevauchement
+     * @param levels liste des niveaux à tracer
+     * @param textHeight hauteur minimal entre le texte des niveaux (m)
+     * @param left true pour tracer le texte à gauche du niveau, false à droite
      */
-    private Xm2pix(x: number) {
-        return this._textMargin + x * this._scaleX;
-    }
+    private drawLevelsWithoutOverlap(levels: any, textHeight: number, left: boolean) {
+        for (let i = levels.length - 1; i >= 0; i--) {
+            const l = levels[i];
 
-    /**
-     * convertit une ordonnée en m en pixels
-     */
-    private Ym2pix(y: number) {
-        return this._size - this._bottomMargin - y * this._scaleY;
-    }
+            // chevauchement avec le précédent ?
+            if (i < levels.length - 1) {
+                let yprec = levels[i + 1].y;
 
-    private sortLevels() {
-        this._levels.sort((a, b) => {
-            if (a["val"] < b["val"]) {
-                return -1;
+                const ycurr = l.y;
+                if (yprec - ycurr < textHeight) {
+                    l.y = yprec - textHeight;
+                }
             }
-            if (a["val"] > b["val"]) {
-                return 1;
+
+            // tracé du tirant courant
+            const col = l["rgb"];
+            this.setStrokeColor(col["r"], col["g"], col["b"]);
+            this.drawSectionLine(0, l.val, this._Wsect_m, l.val);
+            this.setFillColor(col["r"], col["g"], col["b"]);
+
+            if (left) {
+                this.drawText(l["label"], 0, l.y, "right");
+            } else {
+                this.drawText(l["label"], this._Wsect_m, l.y, "left");
             }
-            return 0;
-        });
+        }
     }
 
-    private drawLevels(maxWidth: number) {
-        let left = true;
-
+    private drawLevels() {
         this.resetLineDash();
         this.setLineWidth(1);
-        this.setFont("12px sans- serif");
+        this.setFont("12px sans-serif");
+
+        // hauteur des caractères
+        const tm: TextMetrics = this._context2d.measureText("Ag");
+        const charHeightPix = tm.actualBoundingBoxAscent + tm.actualBoundingBoxDescent;
+        const charHeightMeter = charHeightPix / this._scaleY;
+
+        // sépare les niveaux de gauche/droite
+        const leftLevels = [];
+        const rightLevels = [];
+        let left = true;
         for (const l of this._levels) {
             const y = l["val"];
-            const col = l["rgb"];
-            this.setStrokeColor(col["r"], col["g"], col["b"]);
-            this.drawSectionLine(0, y, maxWidth, y);
-
-            this.setFillColor(col["r"], col["g"], col["b"]);
+            Object.assign(l, { "y": y }); // y = ordonnée de tracé
             if (left) {
-                this.drawText(l["label"], -0.1, y, "right");
+                leftLevels.push(l);
             } else {
-                this.drawText(l["label"], maxWidth + 0.1, y, "left");
+                rightLevels.push(l);
             }
             left = !left;
         }
+
+        // dessin des textes
+        this.drawLevelsWithoutOverlap(leftLevels, charHeightMeter, true);
+        this.drawLevelsWithoutOverlap(rightLevels, charHeightMeter, false);
     }
 
     // contour du canvas
     private drawFrame() {
-        this.clear();
         this.resetLineDash();
         this.setStrokeColor(128, 128, 128);
-        this.drawRect(0, 0, this.width, this.height);
+        this.drawRect(0, 0, this._size, this._size);
     }
 
     public clear() {
         if (this._context2d) {
-            this._context2d.clearRect(0, 0, this.width, this.height);
+            this._context2d.clearRect(0, 0, this._size, this._size);
         }
     }
 
@@ -426,10 +623,17 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.fillStyle = col;
     }
 
-    public setFont(f: string) {
+    private setFont(f: string) {
         this._context2d.font = f;
     }
 
+    /**
+     * dessine un texte sur le canvas
+     * @param s texte à dessiner
+     * @param x position horizontale (pixels)
+     * @param y position verticale (pixels)
+     * @param align alignement "left" ou "right" cf. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
+     */
     public fillText(s: string, x: number, y: number, align?: any) {
         if (align) {
             this._context2d.textAlign = align;
@@ -475,4 +679,8 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle);
         this._context2d.stroke();
     }
+
+    public get uitextUseRealRatio(): string {
+        return this.intlService.localizeText("INFO_SECTIONPARAMETREE_REAL_RATIO");
+    }
 }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 47688d87d2ba2a837da73976e70fb790006c475f..4416adeefc9d8d8fd7f01f41a3cbef17676693aa 100755
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -587,6 +587,7 @@
     "INFO_SECTIONPARAMETREE_DESCRIPTION": "open-channel canal rectangular circular trapezoidal depth head normal critical conjugate corresponding subcritical supercritical Froude",
     "INFO_SECTIONPARAMETREE_TITRE_COURT": "Param. section",
     "INFO_SECTIONPARAMETREE_TITRE": "Parametric section",
+    "INFO_SECTIONPARAMETREE_REAL_RATIO": "Apply 1:1 scale",
     "INFO_SELECT_MULTIPLE_AND_OTHER": "other",
     "INFO_SELECT_MULTIPLE_AND_OTHERS": "others",
     "INFO_SETUP_ENABLE_HOTKEYS": "Enable keyboard shortcuts",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index edbbcf847f55fd237f850dd13ff2d85ea39a485b..4161aea6c0d2697cff2267b91eeb73ed698299ed 100755
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -588,6 +588,7 @@
     "INFO_SECTIONPARAMETREE_DESCRIPTION": "hydraulique à surface libre canal chenal bief rectangulaire circulaire puissance trapézoïdale périmètre charge mouillée rugosité hauteur charge critique normal conjuguée correspondante fluvial torrentiel Froude",
     "INFO_SECTIONPARAMETREE_TITRE_COURT": "Sec. param.",
     "INFO_SECTIONPARAMETREE_TITRE": "Section paramétrée",
+    "INFO_SECTIONPARAMETREE_REAL_RATIO": "Respecter l'échelle",
     "INFO_SELECT_MULTIPLE_AND_OTHER": "autre",
     "INFO_SELECT_MULTIPLE_AND_OTHERS": "autres",
     "INFO_SETUP_ENABLE_HOTKEYS": "Activer les raccourcis clavier",