diff --git a/src/app/calculators/pab/pab.config.json b/src/app/calculators/pab/pab.config.json new file mode 100644 index 0000000000000000000000000000000000000000..fc2ad396c93cf0525d8459d68a1d4fac32050528 --- /dev/null +++ b/src/app/calculators/pab/pab.config.json @@ -0,0 +1,103 @@ +[ + { + "id": "fs_param_hydro", + "type": "fieldset", + "calcType": "Pab", + "option": "cal", + "fields": [ + { + "type": "input", + "id": "Q", + "symbol": "Q", + "unit": "m³/s" + }, + { + "type": "input", + "id": "Z1", + "unit": "m" + }, + { + "type": "input", + "id": "Z2", + "unit": "m" + } + ] + }, + { + "id": "fs_bassin", + "type": "fieldset_template", + "option": "fix", + "fields": [ + { + "id": "select_modele_cloisons", + "type": "select", + "select": [ + { + "id": "select_ouvrage_vanne_rect", + "enum": "StructureType.VanneRectangulaire" + }, + { + "id": "select_ouvrage_seuil_rect", + "enum": "StructureType.SeuilRectangulaire" + }, + { + "id": "select_ouvrage_seuil_triang", + "enum": "StructureType.SeuilTriangulaire" + }, + { + "id": "select_ouvrage_seuil_triangtrunc", + "enum": "StructureType.SeuilTriangulaireTrunc" + } + ] + }, + { + "type": "input", + "id": "ZDV", + "unit": "m", + "nodeType": "StructureRectangle", + "dep_exist": [ + { + "refid": "select_ouvrage", + "refvalue": "select_ouvrage_vanne_rect" + }, + { + "refid": "select_ouvrage", + "refvalue": "select_ouvrage_seuil_rect" + }, + { + "refid": "select_ouvrage", + "refvalue": "select_ouvrage_seuil_triang" + }, + { + "refid": "select_ouvrage", + "refvalue": "select_ouvrage_seuil_triangtrunc" + } + ] + } + ] + }, + { + "id": "bassin_container", + "type": "template_container", + "templates": [ + "fs_bassin" + ] + }, + { + "id": "fs_param_calc", + "type": "fieldset", + "calcType": "ParallelStructure", + "option": "fix", + "fields": [ + { + "type": "input", + "id": "Pr" + } + ] + }, + { + "type": "options", + "modeleCloisonsSelectId": "select_modele_cloisons", + "idCal": "Q" + } +] \ No newline at end of file diff --git a/src/app/calculators/pab/pab.en.json b/src/app/calculators/pab/pab.en.json new file mode 100644 index 0000000000000000000000000000000000000000..955f0fb0b24f5959de7fe3e36d90b31319a9e524 --- /dev/null +++ b/src/app/calculators/pab/pab.en.json @@ -0,0 +1,9 @@ +{ + "fs_param_hydro": "Hydraulic parameters", + "Q": "Flow", + "Z1": "Upstream elevation", + "Z2": "Downstream elevation", + "fs_bassin": "Basin", + "bassin_container": "Basins", + "select_modele_cloisons": "Cross walls model" +} \ No newline at end of file diff --git a/src/app/calculators/pab/pab.fr.json b/src/app/calculators/pab/pab.fr.json new file mode 100644 index 0000000000000000000000000000000000000000..e64d3e88f486d8b13c804f55d91e593b0855a963 --- /dev/null +++ b/src/app/calculators/pab/pab.fr.json @@ -0,0 +1,9 @@ +{ + "fs_param_hydro": "Paramètres hydrauliques", + "Q": "Débit", + "Z1": "Cote amont", + "Z2": "Cote aval", + "fs_bassin": "Bassin", + "bassin_container": "Bassins", + "select_modele_cloisons": "Modèle de cloisons" +} \ No newline at end of file diff --git a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts index 0fc7928626554a2c86fae9bd460a7bb0d1758bd1..3b868359886c34ed418697f8fcadaa132edf0101 100644 --- a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts +++ b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts @@ -2,7 +2,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; import { Inject, Component } from "@angular/core"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; +import { FormBuilder } from "@angular/forms"; @Component({ selector: "dialog-generate-pab", @@ -11,13 +11,13 @@ import { FormGroup, FormBuilder, Validators } from "@angular/forms"; }) export class DialogGeneratePABComponent { - public debit: number; + public debit = 1.5; - public coteAmont: number; + public coteAmont = 102; - public coteAval: number; + public coteAval = 99; - public nbBassins: number; + public nbBassins = 6; constructor( public dialogRef: MatDialogRef<DialogGeneratePABComponent>, diff --git a/src/app/config.json b/src/app/config.json index 86e823ea8cf12655218c8722e3bce223aaf2341a..19625acb4c41e2b281b7f1674e1d803057b980ea 100644 --- a/src/app/config.json +++ b/src/app/config.json @@ -13,7 +13,7 @@ "title": "Passe à poisson sur le Lez, entre Bollène et Suze", "credits": "Hervé Capra / Irstea" }, - "calculators": [ 5, 6, 12, 13, 10, 9 ] + "calculators": [ 15, 5, 6, 12, 13, 10, 9 ] }, { "name": "PASSE_NATURELLE", diff --git a/src/app/formulaire/definition/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts new file mode 100644 index 0000000000000000000000000000000000000000..ade58a60e42f57b48b491ab49f369b4c14874ed5 --- /dev/null +++ b/src/app/formulaire/definition/concrete/form-pab.ts @@ -0,0 +1,269 @@ +import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session } from "jalhyd"; + +import { FormDefParallelStructures } from "../form-def-parallel-structures"; +import { FormComputeParallelStructures } from "../form-compute-parallel-structures"; +import { FormResultFixedVar } from "../form-result-fixedvar"; +import { FieldsetContainer } from "../../fieldset-container"; +import { FieldSet } from "../../fieldset"; +import { SelectField } from "../../select-field"; +import { NgParameter } from "../../ngparam"; +import { FieldsetTemplate } from "../../fieldset-template"; +import { FormulaireNode } from "../../formulaire-node"; +import { FormulaireBase } from "./form-base"; + +/** + * Formulaire pour les passes à bassins, inspiré du formulaire + * pour les structures en parallèle + */ +export class FormulairePab extends FormulaireBase { + + private _formParallelStruct: FormDefParallelStructures; + + /** id du select configurant le modèle de cloisons */ + private __modeleCloisonsSelectId: string; + + constructor() { + super(); + this._formResult = new FormResultFixedVar(this, false); + this._formParallelStruct = new FormDefParallelStructures(); + + // remove obsolete observer set by super() + this.removeObserver(this._formCompute); + this._formCompute = new FormComputeParallelStructures(this, this._formParallelStruct, (this._formResult as FormResultFixedVar)); + } + + private createStructNub(templ: FieldsetTemplate): Nub { + // !!! attention !!! + // Il doit y avoir cohérence dans le fichier de conf entre les valeurs defaultXXX et les valeurs possibles pour les select + // cad valeur par défaut du 1er select (type d'ouvrage), du 2ème (loi de débit). + // A terme, il faudrait analyser le fichier de conf (dépendances d'existence) pour déterminer automatiquement ces valeurs + + const params = {}; + params["calcType"] = templ.calcTypeFromConfig; + params["nodeType"] = templ.defaultNodeTypeFromConfig; + params["structureType"] = templ.defaultStructTypeFromConfig; + params["loiDebit"] = templ.defaultLoiDebitFromConfig; + + return this.createStructure(new Props(params)); + } + + /** + * ajoute un Nub Structure + * @param st structure à ajouter + * @param after position après laquelle insérer la structure, à la fin sinon + */ + private addStructureNub(st: Structure, after?: number) { + this.parallelStructureNub.addChild(st, after); + } + + private get parallelStructureNub(): ParallelStructure { + return this.currentNub as ParallelStructure; + } + + /** + * Asks JaLHyd to create a Structure Nub as a child of the current Calculator Module + * and return it; does not store it in the Session (for Structures, not for Calculator Modules) + * @param p properties for the new Nub + */ + protected createStructure(p: Props): Structure { + return Session.getInstance().createNub(p, this.currentNub as ParallelStructure) as Structure; + } + + /** + * Replaces the current Nub in the current calculator module, with a new one built with properties "params" + * @param params properties to build the new Nub (calcType, loiDebit...) + */ + protected replaceNub(sn: Structure, params: Props): Nub { + const parent = (this.currentNub as ParallelStructure); + const newStructure = this.createStructure(params); + parent.replaceChildInplace(sn, newStructure); + return newStructure; + } + + /** + * Deleted the given child Nub in the current calculator module + * @param params properties to build the new Nub (calcType, loiDebit...) + */ + protected deleteNub(sn: Structure) { + const parent = (this.currentNub as ParallelStructure); + parent.deleteChild(parent.getIndexForChild(sn)); + } + + public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet { + if (json["calcType"] === "Structure") { + // indice après lequel insérer le nouveau FieldSet + const after = data["after"]; + + const res: FieldSet = new FieldSet(parent); + let sn: Nub; + if (nub) { // use existing Nub (build interface based on model) + sn = nub; + } else { + sn = this.createStructNub(data["template"]); + this.addStructureNub(sn as Structure, after); + } + res.setNub(sn, false); + + if (after !== undefined) { + parent.kids.splice(after + 1, 0, res); + } else { + parent.kids.push(res); + } + + this.resetResults(); + + return res; + } else { + return super.createFieldset(parent, json, data); + } + } + + protected parseOptions(json: {}) { + super.parseOptions(json); + + // id du select configurant le type d'ouvrage + this.__modeleCloisonsSelectId = this.getOption(json, "ouvrageSelectId"); + } + + public afterParseFieldset(fs: FieldSet) { + // si le FieldSet contient le select de type d'ouvrage + if (this.__modeleCloisonsSelectId) { + const sel = fs.getFormulaireNodeById(this.__modeleCloisonsSelectId); + if (sel) { + // on abonne le formulaire aux propriétés du FieldSet + fs.properties.addObserver(this); + } + } + } + + public moveFieldsetUp(fs: FieldSet) { + if (fs.nub instanceof Structure) { + // déplacement du nub + fs.nub.parent.moveChildUp(fs.nub); + // déplacement du fieldset + this.fieldsetContainer.moveFieldsetUp(fs); + + this.resetResults(); + } else { + super.moveFieldsetUp(fs); + } + } + + public moveFieldsetDown(fs: FieldSet) { + if (fs.nub instanceof Structure) { + // déplacement du nub + fs.nub.parent.moveChildDown(fs.nub); + // déplacement du fieldset + this.fieldsetContainer.moveFieldsetDown(fs); + + this.resetResults(); + } else { super.moveFieldsetDown(fs); } + } + + public removeFieldset(fs: FieldSet) { + if (fs.nub instanceof Structure) { + // suppression du sous-nub dans le Nub parent + this.deleteNub(fs.nub); + + // suppression du fieldset + this.fieldsetContainer.removeFieldset(fs); + + this.resetResults(); + } else { super.removeFieldset(fs); } + } + + protected completeParse(json: {}) { + this._formParamCalc.parseOptions(json); + this.subscribeFieldsetContainer(); + } + + private get fieldsetContainer(): FieldsetContainer { + const n = this.getFormulaireNodeById("bassin_container"); + if (n === undefined || !(n instanceof FieldsetContainer)) { + throw new Error("l'élément 'bassin_container' n'est pas du type FieldsetContainer"); + } + return n as FieldsetContainer; + } + + /** + * Après une modification, détermine si les propriétés d'un Fieldset sont compatibles + * entre elles et les ajuste au besoin + * @param props propriétés à vérifier + * @param name nom de la propriété qui vient de changer + * @param val nouvelle valeur de la propriété + */ + private adjustProperties(props: Props, name: string, val: any) { + if (name === "structureType") { + if (! StructureProperties.isCompatibleValues( + val, props.getPropValue("loiDebit"), this.currentNub as ParallelStructure + )) { + // currentNub should always be a ParallelStructure here + const ld = StructureProperties.findCompatibleLoiDebit( + props.getPropValue("structureType"), + [], + this.currentNub as ParallelStructure + ); + props.setPropValue("loiDebit", ld); + } + } + } + + /** + * abonnement en tant qu'observateur du FieldsetContainer + */ + private subscribeFieldsetContainer() { + this.fieldsetContainer.addObserver(this); + } + + /** + * abonnement en tant qu'observateur des NgParameter des FieldSet contenus dans le FieldsetContainer + */ + private subscribeStructureInputFields(fs: FieldSet) { + for (const n of fs.allFormElements) { + if (n instanceof NgParameter) { + n.addObserver(this); + } + } + } + /** + * abonnement en tant qu'observateur du SelectField des FieldSet contenus dans le FieldsetContainer + */ + private subscribeStructureSelectFields(fs: FieldSet) { + for (const n of fs.allFormElements) { + if (n instanceof SelectField) { + n.addObserver(this); + } + } + } + + // interface Observer + + public update(sender: any, data: any) { + + super.update(sender, data); + + if (sender instanceof FieldsetContainer) { + switch (data.action) { + case "newFieldset": + this.reset(); + this.subscribeStructureInputFields(data["fieldset"]); + this.subscribeStructureSelectFields(data["fieldset"]); + } + } else if (sender instanceof FieldSet && data.action === "propertyChange") { + switch (sender.id) { + case "fs_ouvrage": + const props = sender.properties; + // ensure loiDebit is set + props.setPropValue("loiDebit", data.value); + this.adjustProperties(props, data["name"], data["value"]); + // replace Structure Nub + const newNub = this.replaceNub((sender.nub as Structure), props); + sender.setNub(newNub); + // treat the fieldset as new to re-subscribe to Nub properties change events + this.afterParseFieldset(sender); + this.reset(); + break; + } + } + } +} diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts index 2d703d83205641f1085b9c67dd6990564df10a73..5a45fdaf37eaa1bab5d2e2c69a6f9797e9f9e608 100644 --- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts +++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts @@ -1,4 +1,4 @@ -import { Structure, Nub, ParallelStructure, LoiDebit, StructureProperties, Props, Session, StructureType } from "jalhyd"; +import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session } from "jalhyd"; import { FormDefParallelStructures } from "../form-def-parallel-structures"; import { FormComputeParallelStructures } from "../form-compute-parallel-structures"; diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts index 8490ef82890f7d2655bfcd6b4289e45e05f3afd2..2d722c70e7181c673e1e19691fb55a1224c53ef6 100644 --- a/src/app/services/formulaire/formulaire.service.ts +++ b/src/app/services/formulaire/formulaire.service.ts @@ -22,6 +22,7 @@ import { NgParameter } from "../../formulaire/ngparam"; import { FieldsetContainer } from "../..//formulaire/fieldset-container"; import { ApplicationSetupService } from "../app-setup/app-setup.service"; import { NotificationsService } from "../notifications/notifications.service"; +import { FormulairePab } from "../../formulaire/definition/concrete/form-pab"; @Injectable() export class FormulaireService extends Observable { @@ -60,6 +61,7 @@ export class FormulaireService extends Observable { this.calculatorPaths[CalculatorType.Dever] = "dever"; this.calculatorPaths[CalculatorType.Cloisons] = "cloisons"; this.calculatorPaths[CalculatorType.MacroRugo] = "macrorugo"; + this.calculatorPaths[CalculatorType.Pab] = "pab"; } private get _intlService(): I18nService { @@ -213,6 +215,10 @@ export class FormulaireService extends Observable { f = new FormulaireParallelStructure(); break; + case CalculatorType.Pab: + f = new FormulairePab(); + break; + default: f = new FormulaireBase(); } diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index fa3305255f91f5472f3bcdf4fa0c7fcb965b4986..9f148f5cd7bc200938db79b1b10161e4398f0878 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -167,6 +167,8 @@ "INFO_OPTION_NONE_F": "None", "INFO_OPTION_GENERATE": "Generate", "INFO_OUVRAGE": "Structure", + "INFO_PAB_TITRE": "Fish ladder", + "INFO_PAB_TITRE_COURT": "Fish ladder", "INFO_PABCHUTE_TITRE": "Fish ladder: fall", "INFO_PABCHUTE_TITRE_COURT": "FL: fall", "INFO_PABDIMENSIONS_TITRE": "Fish ladder: dimensions", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index a6ecf9213b9fbc66a24f7f73775cf65979f5e45b..3e0b05940fec7529c9bf432761daabb848bb2c21 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -167,6 +167,8 @@ "INFO_OPTION_NONE_F": "Aucune", "INFO_OPTION_GENERATE": "Générer", "INFO_OUVRAGE": "Ouvrage", + "INFO_PAB_TITRE": "Passe à bassins", + "INFO_PAB_TITRE_COURT": "PAB", "INFO_PABCHUTE_TITRE": "Passe à bassin : chute", "INFO_PABCHUTE_TITRE_COURT": "PAB : chute", "INFO_PABDIMENSIONS_TITRE": "Passe à bassin : dimensions",