formulaire.service.ts 33.44 KiB
import { Injectable } from "@angular/core";
import { decode } from "he";
import {
CalculatorType,
LinkedValue,
Observable,
ParamDefinition,
Session,
Nub,
ParallelStructure,
Pab,
Props,
Cloisons,
CloisonAval,
SPP,
PreBarrage,
PbBassin,
PbBassinParams,
LoiDebit,
PbCloison,
CreateStructure,
Structure,
SectionNub,
SectionParametree,
acSection,
round,
RegimeUniforme,
CourbeRemous
} from "jalhyd";
import { ApplicationSetupService } from "./app-setup.service";
import { HttpService } from "./http.service";
import { I18nService } from "./internationalisation.service";
import { NotificationsService } from "./notifications.service";
import { FormulaireDefinition } from "../formulaire/definition/form-definition";
import { FormulaireElement } from "../formulaire/elements/formulaire-element";
import { InputField } from "../formulaire/elements/input-field";
import { SelectField } from "../formulaire/elements/select/select-field";
import { FormulaireSectionParametree } from "../formulaire/definition/form-section-parametree";
import { FormulaireCourbeRemous } from "../formulaire/definition/form-courbe-remous";
import { FormulaireParallelStructure } from "../formulaire/definition/form-parallel-structures";
import { NgParameter } from "../formulaire/elements/ngparam";
import { FieldsetContainer } from "../formulaire/elements/fieldset-container";
import { FormulairePab } from "../formulaire/definition/form-pab";
import { FormulaireMacrorugoCompound } from "../formulaire/definition/form-macrorugo-compound";
import { FormulaireGrille } from "../formulaire/definition/form-grille";
import { FormulaireSolveur } from "../formulaire/definition/form-solveur";
import { AppComponent } from "../app.component";
import { FormulaireSPP } from "../formulaire/definition/form-spp";
import { FormulaireFixedVar } from "../formulaire/definition/form-fixedvar";
import { FormulaireSection } from "../formulaire/definition/form-section";
import { FormulairePAR } from "../formulaire/definition/form-par";
import { FormulaireVerificateur } from "../formulaire/definition/form-verificateur";
import { FormulaireEspece } from "../formulaire/definition/form-espece";
import { FormulairePrebarrage } from "../formulaire/definition/form-prebarrage";
import { ServiceFactory } from "./service-factory";
import { FormulairePressureLoss } from "app/formulaire/definition/form-pressureloss";
import { getNubResultUnit } from "jalhyd";
import { FormulaireMacroRugoRemous } from "app/formulaire/definition/form-macrorugo-remous";
@Injectable()
export class FormulaireService extends Observable {
/** list of known forms */
private _formulaires: FormulaireDefinition[];
private _currentFormId: string = null;
public static getConfigPathPrefix(ct: CalculatorType): string {
const ctName = CalculatorType[ct].toLowerCase();
return "app/calculators/" + ctName + "/";
}
constructor(
private i18nService: I18nService,
private appSetupService: ApplicationSetupService,
private httpService: HttpService,
private intlService: I18nService,
private notificationsService: NotificationsService
) {
super();
this.clearFormulaires();
}
public get formulaires(): FormulaireDefinition[] {
return this._formulaires;
}
/** Removes all formulaires from the list */
public clearFormulaires() {
this._formulaires = [];
}
/**
* Retourne le titre complet du type de module de calcul, dans la langue en cours
*/
public getLocalisedTitleFromCalculatorType(type: CalculatorType) {
const sCalculator: string = CalculatorType[type].toUpperCase();
return this.intlService.localizeText(`INFO_${sCalculator}_TITRE`);
}
/**
* Retourne la description du type de module de calcul, dans la langue en cours
*/
public getLocalisedDescriptionFromCalculatorType(type: CalculatorType) {
const sCalculator: string = CalculatorType[type].toUpperCase();
return this.intlService.localizeText(`INFO_${sCalculator}_DESCRIPTION`);
}
/**
* Retourne le titre cour du type de module de calcul, dans la langue en cours
* (pour les titres d'onglets par défaut)
*/
public getLocalisedShortTitleFromCalculatorType(type: any) {
if (typeof type !== "string") { // retrocompatibility for old file format
type = CalculatorType[type];
}
const sCalculator: string = type.toUpperCase();
return this.intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`);
}
/**
* Forces update of all form strings in given Formulaire, with current language
*/
public updateFormulaireLocalisation(f: FormulaireDefinition) {
const requiredLang = this.intlService.currentLanguage;
f.updateLocalisation(requiredLang);
}
/**
* Tente de trouver une traduction pour textKey dans les fichiers de langues
* spécifiques du module de calcul en cours, dans la langue en cours, puis
* dans la langue par défaut; si aucune traduction n'est trouvée, demande au
* service i18n de rechercher dans les fichiers de langues globaux
* @param textKey la clé du texte à traduire
*/
public localizeText(textKey: string, ct: CalculatorType): string {
const calcType = /* this.currentForm?.currentNub?.calcType || */ ct;
if (calcType !== undefined) {
// throw new Error("FormulaireService.localizeText(): cannot find CalculatorType for current form's Nub");
let langCache = this.i18nService.languageCache;
if (langCache && langCache[calcType]) {
langCache = langCache[calcType]; // …for target Nub type
}
// try current language
if (
langCache
&& langCache[this.intlService.currentLanguage]
&& langCache[this.intlService.currentLanguage][textKey] !== undefined
) {
return langCache[this.intlService.currentLanguage][textKey];
}
}
// fallback to global (not calculator type specific) translation system
return this.i18nService.localizeText(textKey);
}
/**
* Returns variable name from symbol
* @param calcType
* @param symbol
*/
public expandVariableName(calcType: CalculatorType, symbol: string): string {
let s = "";
// language cache…
let langCache = this.i18nService.languageCache;
if (langCache && langCache[calcType]) {
langCache = langCache[calcType]; // …for target Nub type
}
if (langCache && langCache[this.intlService.currentLanguage]) {
langCache = langCache[this.intlService.currentLanguage]; // … for current language
}
if (langCache && langCache[symbol] !== undefined) {
s = this.localizeText(symbol, calcType);
} else {
// is symbol of the form ouvrages[i]… ?
const re = /([A-Z,a-z]+)\[(\d+)\]\.(.+)/;
const match = re.exec(symbol);
if (match) {
// Les libellés correspondants sont INFO OUVRAGE et INFO_LIB_OUVRAGE_XXX
s = this.intlService.localizeText(`INFO_${match[1].toUpperCase()}`)
+ " n°" + (+match[2] + 1) + ": "
+ this.expandVariableName(calcType, `${match[1].toUpperCase()}_${match[3].toUpperCase()}`);
} else {
s = this.intlService.localizeText("INFO_LIB_" + symbol.toLocaleUpperCase());
}
}
return s;
}
/**
* Returns variable name and unit from symbol
* @param calcType
* @param symbol
* @param forceUnit if given, will be used as unit
*/
public expandVariableNameAndUnit(calcType: CalculatorType, symbol: string, forceUnit?: string): string {
let s = this.expandVariableName(calcType, symbol);
let langCache = this.i18nService.languageCache; // language cache…
if (langCache && langCache[calcType]) {
langCache = langCache[calcType]; // …for target Nub type
}
if (langCache && langCache[this.intlService.currentLanguage]) {
langCache = langCache[this.intlService.currentLanguage]; // … for current language
}
// remove device number before looking for unit (hacky)
let symbolBase = symbol.toLocaleUpperCase();
const idx = symbolBase.indexOf("].");
if (idx !== -1) {
symbolBase = symbolBase.substring(idx + 2);
}
let unit: string;
// unit of a parameter is supposed to be read from JaLHyd ParadDefinition and passed
// through "forceUnit"; keys like "UNIT_*" in the config file are for extra results
if (forceUnit) {
unit = forceUnit;
} else {
unit = getNubResultUnit(calcType, symbol);
if (unit === undefined) {
// last chance: if unit cannot be read in model, use translation files
const unitKey = "UNIT_" + symbolBase;
if (langCache && langCache[unitKey] !== undefined) {
unit = this.localizeText(unitKey, calcType);
}
}
}
if (unit) {
s = s + " (" + unit + ")";
}
return s;
}
/**
* From https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
*/
private escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
/**
* Checks if the given calculator name (tab title) is already used by any existing
* form; if so, adds a number after it
*/
private suffixNameIfNeeded(name: string) {
let found = false;
let maxNumber = 0;
// extract base name
let baseName = name;
const re1 = new RegExp("^.+( \\d+)$");
const matches1 = re1.exec(name);
if (matches1) {
baseName = baseName.replace(matches1[1], "");
}
// browse session calculators
const re2 = new RegExp("^" + this.escapeRegExp(baseName) + "( (\\d+))?$");
for (const f of this.formulaires) {
const matches2 = re2.exec(f.calculatorName);
if (matches2) {
found = true;
if (matches2[2] !== undefined) {
const nb = Number(matches2[2]);
maxNumber = Math.max(maxNumber, nb);
}
}
}
// suffix if needed
if (found) {
name = baseName + " " + (maxNumber + 1);
}
return name;
}
public loadConfig(ct: CalculatorType): Promise<any> {
const f: string = FormulaireService.getConfigPathPrefix(ct) + "config.json";
return this.httpService.httpGetRequestPromise(f);
}
private newFormulaire(ct: CalculatorType): FormulaireDefinition {
let f: FormulaireDefinition;
switch (ct) {
case CalculatorType.SectionParametree:
f = new FormulaireSectionParametree();
break;
case CalculatorType.Bief:
case CalculatorType.RegimeUniforme:
f = new FormulaireSection();
break;
case CalculatorType.CourbeRemous:
f = new FormulaireCourbeRemous();
break;
case CalculatorType.ParallelStructure:
case CalculatorType.Dever:
case CalculatorType.Cloisons:
f = new FormulaireParallelStructure();
break;
case CalculatorType.Pab:
f = new FormulairePab();
break;
case CalculatorType.MacroRugoCompound:
f = new FormulaireMacrorugoCompound();
break;
case CalculatorType.Grille:
f = new FormulaireGrille();
break;
case CalculatorType.Par:
case CalculatorType.ParSimulation:
f = new FormulairePAR();
break;
case CalculatorType.Solveur:
f = new FormulaireSolveur();
break;
case CalculatorType.SPP:
f = new FormulaireSPP();
break;
case CalculatorType.Verificateur:
f = new FormulaireVerificateur();
break;
case CalculatorType.Espece:
f = new FormulaireEspece();
break;
case CalculatorType.PreBarrage:
f = new FormulairePrebarrage();
break;
case CalculatorType.PressureLoss:
f = new FormulairePressureLoss();
break;
case CalculatorType.MacroRugoRemous:
f = new FormulaireMacroRugoRemous();
break;
default:
f = new FormulaireFixedVar();
}
f.defaultProperties["calcType"] = ct;
return f;
}
/**
* crée un formulaire d'un type donné
* @param ct type de formulaire
* @param nub nub existant à associer au formulaire (chargement de session / duplication de module)
* @param calculatorName nom du module, à afficher dans l'interface
*/
public async createFormulaire(ct: CalculatorType, nub?: Nub, calculatorName?: string): Promise<FormulaireDefinition> {
// Crée un formulaire du bon type
const f: FormulaireDefinition = this.newFormulaire(ct);
this._formulaires.push(f);
// Charge la configuration dépendamment du type
const s: any = await this.loadConfig(ct);
f.preparseConfig(s);
// Associe le Nub fourni (chargement de session / duplication de module), sinon en crée un nouveau
if (nub) {
f.currentNub = nub;
} else {
const confProps = f.parseConfigToProps();
confProps.setPropValue("calcType", ct);
f.initNub(confProps);
}
// Restaure le nom du module, sinon affecte le nom par défaut
let tempName: string;
if (calculatorName) {
tempName = calculatorName;
} else {
tempName = decode(this.getLocalisedShortTitleFromCalculatorType(ct));
}
// Suffixe le nom du module si nécessaire
f.calculatorName = this.suffixNameIfNeeded(tempName);
f.parseConfig();
// add fieldsets for existing Structures if needed
// (when loading session only)
if (f.currentNub instanceof ParallelStructure) {
for (const struct of f.currentNub.structures) {
for (const e of f.allFormElements) {
if (e instanceof FieldsetContainer) { // @TODO manage many containers one day ?
e.addFromTemplate(undefined, struct);
}
}
}
}
// add fieldsets for existing YAXN if needed
// (when loading session only)
if (f.currentNub instanceof SPP) {
for (const c of f.currentNub.getChildren()) {
for (const e of f.allFormElements) {
if (e instanceof FieldsetContainer) { // @TODO manage many containers one day ?
e.addFromTemplate(undefined, c);
}
}
}
}
// when creating a new Pab, add one wall with one device, plus the downwall
// (when loading session, those items are already present)
if (
f instanceof FormulairePab
&& f.currentNub instanceof Pab
&& f.currentNub.children.length === 0
&& f.currentNub.downWall === undefined
) {
// 1. one wall
const newWall = Session.getInstance().createNub(
new Props({
calcType: CalculatorType.Cloisons
})
) as Cloisons;
// add new default device for new wall
const newDevice = Session.getInstance().createNub(
new Props({
calcType: CalculatorType.Structure,
loiDebit: newWall.getDefaultLoiDebit()
})
);
newWall.addChild(newDevice);
f.pabNub.addChild(newWall);
// 2. downwall
const newDownWall = Session.getInstance().createNub(
new Props({
calcType: CalculatorType.CloisonAval
})
) as CloisonAval;
// add new default device for new downwall
const newDownwallDevice = Session.getInstance().createNub(
new Props({
calcType: CalculatorType.Structure,
loiDebit: newDownWall.getDefaultLoiDebit()
})
);
newDownWall.addChild(newDownwallDevice);
f.pabNub.downWall = newDownWall;
}
// when creating a new PreBarrage, add one basin and two walls with one
// device each (when loading session, those items are already present)
if (
f instanceof FormulairePrebarrage
&& f.currentNub instanceof PreBarrage
&& f.currentNub.children.length === 0
) {
const emptyFields: boolean = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit;
// 1 basin
f.currentNub.addChild(new PbBassin(new PbBassinParams(13.80, 95, emptyFields)));
// 1st wall
f.currentNub.addChild(new PbCloison(undefined, f.currentNub.children[0] as PbBassin, undefined, emptyFields));
const s1: Structure = CreateStructure(LoiDebit.WeirCunge80, undefined, undefined, emptyFields);
// s1.prms.ZDV.singleValue = 95.30;
// s1.getParameter("L").singleValue = 0.4;
// s1.getParameter("CdGR").singleValue = 1.04;
f.currentNub.children[1].addChild(s1);
// 2nd wall
f.currentNub.addChild(new PbCloison(f.currentNub.children[0] as PbBassin, undefined, undefined, emptyFields));
const s2: Structure = CreateStructure(LoiDebit.WeirCunge80, undefined, undefined, emptyFields);
// s2.prms.ZDV.singleValue = 95.30;
// s2.getParameter("L").singleValue = 0.4;
// s2.getParameter("CdGR").singleValue = 1.04;
f.currentNub.children[2].addChild(s2);
}
this.notifyObservers({
"action": "createForm",
"form": f
});
return f;
}
/**
* Trick to notify param-link components that parent form name changed
* @TODO find a way to make param-link components directly observe FormDefinition
*/
public propagateFormNameChange(f: FormulaireDefinition, name: string) {
this.notifyObservers({
"action": "formNameChanged",
"form": f,
"value": name
});
}
public getFormulaireFromId(uid: string): FormulaireDefinition {
for (const f of this._formulaires) {
if (f.uid === uid) {
return f;
}
}
}
public getInputField(formId: string, elemId: string): InputField {
const s = this.getFormulaireElementById(formId, elemId);
if (!(s instanceof InputField)) {
throw new Error("Form element with id '" + elemId + "' is not an input");
}
return <InputField>s;
}
public getSelectField(formId: string, elemId: string): SelectField {
const s = this.getFormulaireElementById(formId, elemId);
if (!(s instanceof SelectField)) {
throw new Error("Form element with id '" + elemId + "' is not a select");
}
return <SelectField>s;
}
private getFormulaireElementById(formId: string, elemId: string): FormulaireElement {
for (const f of this._formulaires) {
if (f.uid === formId) {
const s = f.getFormulaireNodeById(elemId);
if (s !== undefined) {
return s as FormulaireElement;
}
}
}
}
public getParamdefParentForm(prm: ParamDefinition): FormulaireDefinition {
for (const f of this._formulaires) {
for (const p of f.allFormElements) {
if (p instanceof NgParameter) {
if (p.paramDefinition.uid === prm.uid) {
return f;
}
}
}
}
}
/**
* retrouve un formulaire à partir d'un uid de Nub
*/
public getFormulaireFromNubId(uid: string) {
for (const f of this._formulaires) {
if (f.hasNubId(uid)) {
return f;
}
}
}
/**
* Supprime le formulaire ciblé, et demande à JaLHyd d'effacer son Nub de la Session
* @param uid formulaire à supprimer
*/
public requestCloseForm(uid: string) {
const form = this.getFormulaireFromId(uid);
const nub = form.currentNub;
if (form) {
this._formulaires = this._formulaires.filter(f => f.uid !== uid);
this.notifyObservers({
"action": "closeForm",
"form": form
});
// reset the result panels of all forms depending on this one
// @TODO UI should detect model change instead of doing this manually
this.resetAllDependingFormsResults(form, [], undefined, true, false);
}
if (nub) {
// reset model results (important, also resets dependent Nubs results in chain)
form.currentNub.resetResult();
Session.getInstance().deleteNub(nub);
}
}
public get currentFormId() {
return this._currentFormId;
}
public setCurrentForm(formId: string) {
const form = this.getFormulaireFromId(formId);
if (form === undefined) {
this._currentFormId = null;
this.notifyObservers({
"action": "invalidFormId",
"formId": formId
});
} else {
this._currentFormId = formId;
this.notifyObservers({
"action": "currentFormChanged",
"formId": formId
});
}
}
public get currentForm(): FormulaireDefinition {
return this.getFormulaireFromId(this._currentFormId);
}
public get currentFormHasResults(): boolean {
const form = this.currentForm;
if (form !== undefined) {
return form.hasResults;
}
return false;
}
private readSingleFile(file: File): Promise<any> {
return new Promise<any>((resolve, reject) => {
const fr = new FileReader();
fr.onload = () => {
resolve(fr.result);
};
fr.onerror = () => {
fr.abort();
reject(new Error(`Erreur de lecture du fichier ${file.name}`));
};
fr.readAsText(file);
});
}
/**
* charge une session en tenant compte des modules de calcul sélectionnés
* @param f fichier session
* @param formInfos infos sur les modules de calcul @see DialogLoadSessionComponent.calculators
*/
public async loadSession(i: Blob | string, formInfos: any[] = []): Promise<{ hasErrors: boolean, loaded: string[] }> {
try {
// disable "empty fields" flag temporarly
const emptyFields = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit;
ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit = false;
let s;
if (i instanceof Blob) {
s = await this.readSingleFile(i as File);
} else {
s = i;
}
const uids: string[] = [];
formInfos.forEach((fi) => {
if (fi.selected) {
uids.push(fi.uid);
}
});
const res = Session.getInstance().unserialise(s, uids);
const newNubs = res.nubs;
// for each new Nub, create the related form, set its title
for (let i = 0; i < newNubs.length; i++) {
const nn = newNubs[i];
let title;
if (nn.meta && nn.meta.title) {
title = nn.meta.title;
}
await this.createFormulaire(nn.nub.calcType, nn.nub, title); // await guarantees loading order
}
// restore "empty fields" flag
ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit = emptyFields;
// apply settings
if (res.settings) {
// model based settings
if (res.settings.precision !== undefined) {
this.appSetupService.computePrecision = res.settings.precision;
}
if (res.settings.maxIterations !== undefined) {
this.appSetupService.maxIterations = res.settings.maxIterations;
}
// GUI settings
if (res.settings.displayPrecision !== undefined) {
this.appSetupService.displayPrecision = res.settings.displayPrecision;
}
}
// forward errors
return {
hasErrors: res.hasErrors,
loaded: newNubs.map(n => n.nub.uid)
};
} catch (err) {
// forward errors to caller to avoid "Uncaught (in promise)"
throw err;
}
}
/**
* Sends an UTF-8 text file for download
*/
public downloadTextFile(session: string, filename: string = "file_1") {
const mt = "text/plain;charset=utf-8";
const blob = new Blob([session], { type: "text/plain;charset=utf-8" });
AppComponent.download(blob, filename, "text/plain");
}
/**
* obtient des infos (nom, uid des modules de calcul, dépendances) d'un fichier session
* @param f fichier session
*/
public async calculatorInfosFromSessionFile(f: File): Promise<{ nubs: any[], formatVersion: string }> {
const s = await this.readSingleFile(f);
// return value
const res: {
nubs: any[];
formatVersion: string;
} = {
nubs: [],
formatVersion: ""
};
const data = JSON.parse(s);
// liste des noms de modules de calcul
if (data.session && Array.isArray(data.session)) {
data.session.forEach((e: any) => {
const nubInfo = {
uid: e.uid,
title: e.meta && e.meta.title ? e.meta.title : undefined,
requires: [],
children: [],
type: e.props.calcType
};
// list linked params dependencies for each Nub
if (e.parameters) {
e.parameters.forEach((p) => {
if (p.targetNub && !nubInfo.requires.includes(p.targetNub)) {
nubInfo.requires.push(p.targetNub);
}
});
}
// list children nubs for each Nub
if (e.children) {
e.children.forEach((p) => {
nubInfo.children.push(p.uid);
});
}
res.nubs.push(nubInfo);
});
}
// version du format de fichier
if (data.header && data.header.format_version) {
res.formatVersion = data.header.format_version;
}
return res;
}
public saveForm(f: FormulaireDefinition) {
this.notifyObservers({
"action": "saveForm",
"form": f
});
}
/**
* Demande à la Session JalHYd la liste des paramètres/résultats pouvant être liés au
* paramètre fourni
*/
public getLinkableValues(p: NgParameter): LinkedValue[] {
let linkableValues: LinkedValue[] = [];
if (p) {
linkableValues = Session.getInstance().getLinkableValues(p.paramDefinition);
// join form names to ease usage
for (let i = 0; i < linkableValues.length; i++) {
const lv = linkableValues[i];
for (const f of this._formulaires) {
if (f.currentNub) {
if (f.currentNub.uid === lv.nub.uid) {
lv.meta["formTitle"] = f.calculatorName;
} else {
// child structures ?
for (const s of f.currentNub.getChildren()) {
if (s.uid === lv.nub.uid) {
lv.meta["formTitle"] = f.calculatorName;
}
}
}
}
}
}
}
linkableValues = this.filterLinkableValues(linkableValues);
return linkableValues;
}
/**
* filtre les valeurs liables à un paramètre :
* - supprime les valeurs non affichées dans leur parent (ce n'est pas le cas par ex
* pour Q, Z1, Z2 dans les ouvrages enfants des ouvrages //)
* @param values valeurs liables (modifié par la méthode)
*/
public filterLinkableValues(values: any[]): any[] {
for (let i = values.length - 1; i >= 0; i--) {
const v = values[i].value;
if (v instanceof ParamDefinition) {
// pour chaque paramètre...
const prm: ParamDefinition = v;
const parentForm: FormulaireDefinition = this.getParamdefParentForm(prm);
// ... on cherche s'il est affiché dans son parent
let found = false;
if (parentForm !== undefined) {
for (const fe of parentForm.allFormElements) {
if (fe instanceof NgParameter) {
if (fe.paramDefinition.uid === prm.uid) {
found = true;
break;
}
}
}
}
if (!found) {
values.splice(i, 1);
}
}
}
return values;
}
/**
* Resets the results of all forms depending on the given form "f"
* @param f
* @param symbol symbol of the parameter whose value change triggered this method
* @param forceResetAllDependencies if true, even non-calculated non-modified parameters
* links will be considered as dependencies @see jalhyd#98
*/
public resetAllDependingFormsResults(
f: FormulaireDefinition,
visited: string[] = [],
symbol?: string,
forceResetAllDependencies: boolean = false,
notify: boolean = true
) {
const dependingNubs = Session.getInstance().getDependingNubs(f.currentNub.uid, symbol, forceResetAllDependencies, true);
for (const dn of dependingNubs) {
if (!visited.includes(dn.uid)) {
const form = this.getFormulaireFromNubId(dn.uid);
if (form) {
const hadResults = form.hasResults;
// form might not have a result, but still have another form depending on it !
// console.debug(`FormulaireService.resetAllDependingFormsResults(form->${dn.uid})`);
form.resetResults(visited);
if (hadResults) {
if (notify) {
this.notificationsService.notify(
this.intlService.localizeText("INFO_SNACKBAR_RESULTS_INVALIDATED") + " " + form.calculatorName,
1500
);
}
}
}
}
}
}
/**
* Génère un formulaire SectionParametree à partir du module courant
* s'il est du type régime uniforme ou courbe de remous
*/
public async generateParametricSectionForm(Y?: number): Promise<FormulaireDefinition> {
if (this.currentForm.currentNub instanceof SectionNub) {
const sn: SectionNub = this.currentForm.currentNub;
if (sn instanceof RegimeUniforme || sn instanceof CourbeRemous) {
// copy section
const serialisedSection = sn.section.serialise();
const sectionCopy: acSection = Session.getInstance().unserialiseSingleNub(serialisedSection, false).nub as acSection;
if (Y !== undefined) {
sectionCopy.prms.Y.singleValue = Y;
}
const secParam = new SectionParametree(sectionCopy);
if (sn instanceof RegimeUniforme) {
// copy value of calculated param
const cp: ParamDefinition = sn.calculatedParam;
const scp: ParamDefinition = secParam.section.getParameter(cp.symbol);
if (cp.hasMultipleValues) {
scp.setValues(sn.result.getCalculatedValues().map(v => round(v, this.appSetupService.displayPrecision)));
} else {
scp.singleValue = sn.result.vCalc;
}
}
Session.getInstance().registerNub(secParam);
return await this.createFormulaire(CalculatorType.SectionParametree, secParam);
}
}
return Promise.reject("cannot create parametric section from current form");
}
}