File

src/app/models/cabri-integration-droitegraduee.ts

Properties

positionBottomY
positionBottomY: number
positionLeftX
positionLeftX: number
positionRightX
positionRightX: number
positionTopY
positionTopY: number
import { CabriDataService } from "../services/cabri-data.service";
import { GlobalService } from "../services/global.service";
import { NgZone, Renderer2 } from "@angular/core";
import { JeuJustePointPage, justePointActivity, operation } from "../page/jeu-juste-point/jeu-juste-point.page";
import {
	BoundingBox,
	DynamicTexture,
	Mesh,
	PickingInfo,
	StandardMaterial,
	Vector3,
	SubMesh,
	AssetsManager,
	AssetContainer,
	AbstractAssetTask,
	MeshAssetTask,
	ImageAssetTask,
	TextureAssetTask,
	AbstractMesh,
	Texture,
	MultiMaterial,
	Observer,
	PointerInfo,
	Animatable,
	Color3,
	Material,
	HighlightLayer,
	EventState,
	Animation,
	Scene,
	PointerEventTypes,
	ArcRotateCamera,
	ArcRotateCameraPointersInput,
	PointerTouch,
	MeshBuilder,
	DefaultLoadingScreen,
	VertexAnimationBaker,
} from "@babylonjs/core";

import { AppUtils, Fraction } from "../app-utils";
import { BabylonJsConfetti, ParticleAnimName } from "./babylonjs-confetti";
// import { JeuJustePointParticles } from "mathjax-angular/types";
import { Subject } from "rxjs";
import { Button, 
	Vector2WithInfo,
	AdvancedDynamicTexture,
	Rectangle,
	StackPanel,
	TextBlock,
	InputText,
} from "@babylonjs/gui";
import * as GUI from '@babylonjs/gui';
import { Control } from "gui4.1";
import { DroiteGradueePage } from "../pages/droite-graduee/droite-graduee.page";
import { BabylonGabaritIntegration } from "./babylon-gabarit-integration";
import { randomInt } from "crypto";
import { NumberLiteralType } from "typescript";

declare var window: {
	store: any;
	document: any;
	innerWidth: any;
	innerHeight: any;
	outerWidth: any;
	outerHeight: any;
	URL: any;
	btoa: any;
	devicePixelRatio: number;
};

export class CollisionPosition {
	positionTopY: number;
	positionBottomY: number;
	positionLeftX: number;
	positionRightX: number;
}

export class TargetMesh extends Mesh {
	value: number | Fraction;
	rangeValue: any;
	draggable: boolean;
	index: number;
	color: string;
	remediation: boolean;
	initialPosition: Vector3;
	visible: boolean;
	diffuseTexture: any;
}

export class TargetSubMesh extends SubMesh {
	value: number | Fraction;
	visible: boolean;
}
export enum DistanceUnit {
	Mm = "Mm",
	Dm = "Dm",
	Cm = "Cm",
	M = "M",
	Dam = "Dam",
	Hm = "Hm",
	Km = "km"
}

export enum Representation {
	Decimale = "D",
	Fraction = "F",
	Scientifique = "S",
	Litherale = "L"
}

export enum Outil {
	Joker = "D",
	Selection = "S",
	Rien = "R"
}

export enum Epreuve {
	Nommer = "N",
	Placer = "P",
}

declare var MathJax: {
	startup: any;
	svg: any;
	tex: any;
	tex2svg: any;
	tex2svgPromise: any;
	loader: any;
	Hub: any;
	config: any;
	tex2mml: any;
	defsGlobalCaching: any;
};

declare var BABYLON;

export interface UserAnswer {
	success: boolean;
	response: number | Fraction | ResultOnTheRoad;
	reversed?: boolean;
}

export class ResultOnTheRoad {
	constructor(error: { color: string; correctValue: number | Fraction }[]) {
		this.carsError = error;
	}
	carsError: { color: string; correctValue: number | Fraction }[];
}
export class BabylonGabaritIntegrationDroiteGraduee extends BabylonGabaritIntegration {
	/*********************************************** */
	/*********************************************** */
	/*********************************************** */
	/*********************************************** */
	/******** affichage */
	nb_graduations_maximal:number=200;
	valeur_de_graduation:number[]=[]
	valeur_de_graduation_trans:number[]=[]
	graduations:string[] = []
	graduations_petites:Mesh[] = []
	graduations_moyennes:Mesh[] = []
	graduations_grandes:Mesh[] = []
	valeur_graduations_petites:number[] = []
	valeur_graduations_moyennes:number[] = []
	valeur_graduations_grandes:number[] = []
	valeur_trans_graduations_petites:number[] = []
	valeur_trans_graduations_moyennes:number[] = []
	valeur_trans_graduations_grandes:number[] = []
	trans_graduations_petites:Mesh[] = []
	trans_graduations_moyennes:Mesh[] = []
	trans_graduations_grandes:Mesh[] = []
	trans_graduations_grandes_etiquettes:Mesh[] = []
	graduations_grandes_etiquettes:Mesh[] = []
	graduations_specifiques_etiquettes:Mesh[] = []
	valeur_etiquete:number[]=[]
	index_specifiques_etiquette:number=0
	index_grand:number=0
	index_moyen:number=0
	index_petit:number=0
	trans_index_grand:number=0
	trans_index_moyen:number=0
	trans_index_petit:number=0
	bg_blanc:Mesh
	couleur_graduation_defaut:StandardMaterial
	couleur_graduation_hover:StandardMaterial
	couleur_graduation_select:StandardMaterial
	segment:Mesh=null
	/********  config affichage systeme*/
	resolution_geo_min:number=0.1 // distance mini entre deux graduation avant chgmt
	resolution_geo_max:number=2.5 // distance max entre deux graduation avant chgmt
	longueur_axe:number=25.0 // longueur theorique de l axe
	longueur_axe_affichee:number=11.3 // longueur effectivement affiché
	sensibilite_zoom:number=0.1 // vitesse zoom dezoom
	sensibilite_translation:number = 10.0 // vitesse translation
	sensibilite_translation_bouton = 0.5
	x:number=0.0 // position affichage x
	y:number=0.0 // position affichage y
	z:number=-1.5 // position affichage z
	longueur_etiquette:number=1.8
	hauteur_etiquette:number=0.6
	hauteur_grande_graduation:number=1.2
	hauteur_moyenne_graduation:number=0.8
	hauteur_petite_graduation:number=0.3
	largeur_grande_graduations:number=0.04
	largeur_moyenne_graduations:number=0.03
	largeur_petite_graduations:number=0.02
	largeur_minimale:number=0.7
	facteur_de_hitbox:number=4.0
	vitesse_translation_auto:number=0.1
	vitesse_zoom_auto:number=0.01
	epaisseur_segment:number=0.05
	/********config affichage d'état */
	position_centre_valeur:number=50.0 // valeur centrale de depart
	position_centre_geo:number=0.0 // excentrage de l affichage de l axe pour translation
	resolution_geo:number=0.2 // distance entre deux graduation
	resolution_valeur:number=1.0 // resolution de depart
	/************ menu **************/
	zoomInBtn:Button // bouton zoom -
	zoomOutBtn:Button // bouton zoom +
	fleche_gauche:Button // bouton fleche gauche
	fleche_droite:Button // bouton fleche droite
	vignette_tentative:TextBlock
	vignette_homotethie:TextBlock
	vignette_translation:TextBlock
	vignette_compte_a_rebour:TextBlock
	vignette_joker:TextBlock
	bouton_joker:Button
	bouton_compte_a_rebour:Button
	bouton_translation:Button
	bouton_homotethie:Button
	bouton_tentative:Button
	attache_curseur:GUI.Image
	gui:AdvancedDynamicTexture
	instruction:GUI.TextBlock
	vignette_etiquette_perso:InputText
	valider_etiquette_perso:Button
	vignette_reponse:InputText
	valider_reponse:Button
	fenetre_instruction:Rectangle
	bouton_instruction:Button
	/*********parametre exercice */
	resolution_maxi:number = 10.0 // resolution maxi
	resolution_mini:number = 0.0001 // resolution mini
	borne_min:number = -1000.0 // borne valeur mini
	borne_max:number = 10000.0 // borne valeur maxi
	affichage_valeurs_graduations_decimales:boolean = true
	representation:Representation = Representation.Decimale
	etiquettes_ajoute:string[]
	etiquettes_supprime:string[]
	tentatives_max:number
	fuel_translation_max:number
	fuel_homotethie_max:number
	limite_temps:number
	nb_joker_max:number
	type_epreuve:Epreuve
	ecart_max_tolere:number
	valeur_a_trouver:number
	sub_graduation_affichable:boolean=true
	activation_du_segment:boolean=false
	/********usage systeme */
	affichage_val_min:number
	affichage_val_max:number
	drag_position_active:number=0
	mouse_px:number=0.0
	mouse_dx:number=0.0
	etiquettes_ajoute_bt:object[]
	etiquettes_supprime_bt:object[]
	tentatives:number
	fuel_translation:number
	fuel_homotethie:number
	compte_a_rebour:number
	nb_joker:number
	type_doutil:Outil
	etiquettes_joker:object[]=[]
	graduation_hover:number[]=[]
	graduation_selectionne:number[]=[]
	les_instructions_a_garder:string=""
	derniere_valeur_choisi:number=0.0
	position_x_curseur_axe:number=0.0
	/*********************************************** */
	/*********************************************** */
	/*********************************************** */
	/*********************************************** */
	generatedMeshElement: Mesh[] = [];
	stepXRange: number;
	bigScaleBars: TargetMesh[] = [];
	smallScaleBars: TargetMesh[] = [];
	tubesMesh: Mesh[] = [];
	targetMeshBrokenBasket: TargetMesh[] = [];
	targetMeshHoop: TargetMesh[] = [];
	background: Mesh;
	targetSubMesh: TargetSubMesh[] = [];
	targetMesh: TargetMesh[] = [];
	linesXPos: number;
	nbBasketItemsRounded: number;
	basketTotalRange: number;
	KPosttargetMesh: TargetMesh[] = [];
	draggablePosition: Vector3;
	basketBallMesh: TargetMesh;
	defaultBallPosition: Vector3;
	defaultBallRotation: Vector3;
	defaultBallScaling: Vector3;
	assetsManagerOnTheRoad: AssetsManager;
	assetsContainerOnTheRoad: AssetContainer;
	assetsManagerBasket: AssetsManager;
	assetsContainerBasket: AssetContainer;
	images: Map<string, HTMLImageElement>;
	textures: Map<string, Texture>;
	materials: Map<string, StandardMaterial>;
	meshs: Map<string, AbstractMesh>;
	pointerObs: Observer<PointerInfo>;
	numberOfElementsDisplayed = new Array();
	currentMesh: Mesh;
	fractionResult: string;
	linePositionY: number;
	hl: HighlightLayer;
	basketRatioElement: number;
	remediationTargettedIndex: number;
	brokenbasket: Mesh;
	hoop: Mesh;
	basketUnitStepPrecision: number;
	hoopNetObservable: Observer<Scene>;

	public waitUserAnswer: Subject<UserAnswer>;

	private babylonLoaded: any;
	advancedTexture;
	bubble;
	textBlock;
	consigne: string[];
	buttonValider: Button;
	color: { color: Color3; name: string }[];
	alpha: number;
	remediationPlanes: Mesh[];
	initialMaterials: Material[];
	mascotteRotation: Vector3;
	consigneScenariosArray: string[];
	lastCalled: number;
	main_axe: Mesh;
	longueur_scene: number;

	constructor(
		public dataService: CabriDataService,
		public globalService: GlobalService,
		public _ngZone: NgZone,
		public page: DroiteGradueePage,
		public renderer: Renderer2
	) {
		super(dataService, globalService, _ngZone, page, renderer);
		this.page = page;
		this.cabriRenderStarted = true;
		// (window as any).justePoint = this;
	}

	onBabylonReady(): Promise<void> {
		return new Promise<void>(async (resolve, reject) => {
			// await super.onBabylonReady();
			
			this.customLoadingScreen();
			// await this.importMascotteMeshes(1.14, 1.2).then(() => {
			// 	const mascotteXUnit = 0.1;
			// 	this.mascotteRotation = new Vector3(
			// 		this.initialCameraPosition.beta + mascotteXUnit - this.initialCameraPosition.beta,
			// 		0,
			// 		0
			// 	);
			// });
			// this.setOrthographicCamera();
			this.addEventPointerOnCanvas();
			// await this.updateCabriPosition(this.dataService.holoMode);
			// this.scene.debugLayer.show({ embedMode: true });
			//this.enableDragAndDrop();
			//this.saveInitialSceneMaterial();
			await this.launchActivity();
			resolve();
		});
	}

	saveInitialSceneMaterial() {
		this.initialMaterials = this.scene.materials.slice();
		this.initialMaterials = this.initialMaterials.concat(this.scene.multiMaterials.slice());
	}

	addEventPointerOnCanvas() {
		super.addEventPointerOnCanvas();
		//(window.store.getters.cabri.Canvas as HTMLCanvasElement).eventListeners("wheel").forEach(eventListener => {
		//	(window.store.getters.cabri.Canvas as HTMLCanvasElement).removeEventListener("wheel", eventListener);
		//});
	}

	async launchActivity() 
    {
        // this.buildscene()   
    }
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
	ordre_de_grandeur(valeur:number):number
	{
		console.log("determination ordre degrandeur")
		let v:number=Math.abs(valeur)
		if(v>=1.0)
		{
			console.log("v>1.0",v);
			let i:number=0
			for(i=0;Math.trunc(v)>0;i++,v=v/10)console.log("t(v)>0",v);
			console.log("renvoi : ",i-1)
			return(i-1)
		}
		else
		{
			console.log("v<1.0",v);
			let i:number=0
			for(i=0;Math.trunc(v)<=0;i++,v=v*10)console.log("t(v)<=0",v);
			return(-i)
		}
	}
	
	trouver_interval_pour_afficher_valeur(valeur:number):[number,number]
	{
		let ordre:number = this.ordre_de_grandeur(valeur)
		let resol:number = Math.pow(10.0,ordre-1)
		let val:number = valeur
		console.log(ordre,resol,val)
		for(;this.longueur_axe/this.resolution_geo*resol+val>=this.borne_max && resol>this.resolution_mini;resol/=10)console.log(resol);
		for(;val-this.longueur_axe/this.resolution_geo*resol<=this.borne_min && resol>this.resolution_mini;resol/=10)console.log(resol);
		for(;resol>this.resolution_maxi;resol/=10);
		val=this.plus_proche_resolution(valeur,this.resolution_valeur)
		return [val,resol]
	}

	resolution_de_valeur(valeur:number):number
	{
		var txt:string=valeur.toFixed(6)
		console.log("txt : "+txt)
		var g:number=txt.length
		for(;txt[g-1]=='0';g--);
		txt=txt.substring(0,g)
		console.log("txt : "+txt)
		var rep:number=Math.pow(10.0,-txt.split(".")[1].length)
		return(rep)
	}

	definir_un_interval_initial_pour_une_valeur(valeur:number)
	{
		[this.position_centre_valeur,this.resolution_valeur]=this.trouver_interval_pour_afficher_valeur(valeur)
		this.position_centre_geo=0.0
	}

	auto_rameneur():void
	{/*
		let tout_est_ok:Boolean=true
		if(this.borne_max<this.affichage_val_max)
		{
			tout_est_ok=false
			this.fleche_gauche.image!.source = "assets/gabarits/droite_graduee/IconeFlecheBlocked-DroiteGradue.webp";
			this.position_centre_geo+=this.resolution_geo
			this.afficher_graduations_entre_deux_valeurs(1.0)
		}
		if(this.borne_min>this.affichage_val_min)
		{
			tout_est_ok=false
			this.fleche_droite.image!.source = "assets/gabarits/droite_graduee/IconeFlecheDroiteBlocked-DroiteGradue.webp";
			this.position_centre_geo-=this.resolution_geo
			this.afficher_graduations_entre_deux_valeurs(1.0)
		}
		if(tout_est_ok)
		{
			this.fleche_gauche.image!.source = "assets/gabarits/droite_graduee/IconeFlecheStart-DroiteGradue.webp";
			this.fleche_droite.image!.source = "assets/gabarits/droite_graduee/IconeFlecheDroiteStart-DroiteGradue.webp";
		}*/
	}

	vision_interdite_translation(deltax:number):boolean
	{
		let minval:number = this.position_centre_valeur-this.longueur_axe_affichee/2.0/this.resolution_geo*this.resolution_valeur-this.position_centre_geo/this.resolution_geo*this.resolution_valeur
		let maxval:number = this.position_centre_valeur+this.longueur_axe_affichee/2.0/this.resolution_geo*this.resolution_valeur-this.position_centre_geo/this.resolution_geo*this.resolution_valeur
		//let dxval:number = deltax*this.resolution_valeur/this.resolution_geo
		//console.log("########################################################\nmin : "+minval.toString())
		if(deltax<0.0)
		{
			if(maxval>this.borne_max)return(true)
		}
		else
		{
			if(minval<this.borne_min)return(true)
		}
		return(false)
	}

	vision_interdite_homotetie(facteur:number):boolean
	{
		var nouv_reso:number=this.resolution_valeur*facteur
		if(nouv_reso<this.resolution_mini*10)
		{
			if(facteur>1.0)return(true)
			else return(false)
		} 
		else if(nouv_reso>this.resolution_maxi/10)
		{
			if(facteur<1.0)return(true)
			else return(false);
		}
		else return(false);
	}
	
	grad_la_plus_proche(x:number):number
	{
		var i:number=0
		if(Math.abs(this.position_centre_geo-x)<this.resolution_geo)return(this.position_centre_geo)
		for(i=0;i<this.nb_graduations_maximal/2-1;i++)
		{
			if(Math.abs(this.position_centre_geo+i*this.resolution_geo-x)<this.resolution_geo)return(this.position_centre_geo+i*this.resolution_geo)
			if(Math.abs(this.position_centre_geo-i*this.resolution_geo-x)<this.resolution_geo)return(this.position_centre_geo-i*this.resolution_geo)
		}
	}
	grad_la_plus_proche_valeur(x:number):number
	{
		return(x-(x%(this.resolution_valeur*10)))
	}
	
	homotetie_graduations(delta:number,x:number):void
	{
		let facteur_homot:number = 1.0
		if(this.fuel_homotethie_max>0)
		{
			if(this.fuel_homotethie<=0)
			{
				this.plus_de_carburant()
				return;
			}
			else this.fuel_homotethie-=0.1
			this.mettre_a_jour_vignettes();
		}
		if(delta>0)
		{
			facteur_homot=1+this.sensibilite_zoom
		}
		else if(delta<0)
		{
			facteur_homot=1-this.sensibilite_zoom
		}
		if(this.vision_interdite_homotetie(facteur_homot))
		{
			if(delta<0)
			{
				//this.zoomInBtn.isEnabled=false
				this.zoomInBtn.image!.source = "assets/gabarits/droite_graduee/Zoom+-Blocked.webp";
			}
			else 
			{
				//this.zoomOutBtn.isEnabled=false
				this.zoomOutBtn.image!.source = "assets/gabarits/droite_graduee/Zoom--Blocked.webp";
			}
			return;
		}
		else
		{
			if(delta>0)
			{
				if(!this.vision_interdite_homotetie(1+this.sensibilite_zoom))
				{
					//this.zoomInBtn.isEnabled=true
					this.zoomInBtn.image!.source = "assets/gabarits/droite_graduee/Zoom+-Start.webp";
				}
			}
			else
			{
				if(!this.vision_interdite_homotetie(1-this.sensibilite_zoom))
				{
					//this.zoomOutBtn.isEnabled=true
					this.zoomOutBtn.image!.source = "assets/gabarits/droite_graduee/Zoom--Start.webp";
				}
			}
		}
		this.resolution_geo*=facteur_homot
		var xgp:number = this.position_x_curseur_axe;//this.grad_la_plus_proche(x)
		this.position_centre_geo=(this.position_centre_geo-xgp)*facteur_homot+xgp
		this.ajustement_de_la_graduation()
		this.afficher_graduations_entre_deux_valeurs(1.0)
	}

	translation_graduations(deltax:number)
	{
		if(this.vision_interdite_translation(deltax))
		{ 
			return;
		}
		if(this.fuel_translation_max>0)
		{
			if(this.fuel_translation<=0.0)
			{
				this.plus_de_carburant();
				return;
			}
			else this.fuel_translation-=Math.abs(deltax)/this.longueur_axe_affichee
			this.mettre_a_jour_vignettes();
		}
		this.position_centre_geo+=deltax
		this.ajustement_de_la_graduation()
		this.afficher_graduations_entre_deux_valeurs(1.0)
	}

	ajustement_de_la_graduation():void
	{
		console.log("update graduation")
		if(this.resolution_geo>this.resolution_geo_max) // AJUSTEMENT ZOOM
		{console.log("homo")
			this.resolution_geo/=10.0
			this.resolution_valeur/=10.0
		}
		else if(this.resolution_geo<this.resolution_geo_min)
		{console.log("homo")
			this.resolution_geo*=10.0
			this.resolution_valeur*=10.0
			var anciene_valeur:number=this.position_centre_valeur
			this.position_centre_valeur=this.grad_la_plus_proche_valeur(this.position_centre_valeur)
			this.position_centre_geo=this.position_centre_geo-(anciene_valeur-this.position_centre_valeur)/this.resolution_valeur*this.resolution_geo
		}
		if(this.position_centre_geo>this.resolution_geo*10)
		{console.log("trans")
			this.position_centre_geo-=this.resolution_geo*10
			this.position_centre_valeur-=this.resolution_valeur*10
		}
		else if(-this.position_centre_geo>this.resolution_geo*10)
		{console.log("trans")
			this.position_centre_geo+=this.resolution_geo*10
			this.position_centre_valeur+=this.resolution_valeur*10
		}
	}

	retrouver_la_mesh_dans(tab:Mesh[],truc:string):number
	{
		let i:number;
		for(i=0;i<tab.length;i++)if(tab[i].id==truc)return(i);
		return(-1);
	}

	le_mesh_survole_qui_est_une_hitbox(tab:PickingInfo[]):Mesh
	{	console.log("----------------------------------quoi vue?------------------------------")
		let i:number
		for(i=0;i<tab.length;i++)
		{
			console.log("vue : "+tab[i].pickedMesh.name)
			if(tab[i].pickedMesh.name.endsWith("_hitBox"))return(tab[i].pickedMesh.parent as Mesh)
		}
		return(undefined)
	}

	trouver_valeur_du_clique(pointerInfo:PointerInfo):number
	{
		const picks = this.scene.multiPickWithRay(
			pointerInfo.pickInfo.ray,
			mesh => mesh.isPickable
		);
		if(picks.length<=0)return(undefined)
		let grad:Mesh=this.le_mesh_survole_qui_est_une_hitbox(picks)
		if(grad==undefined)return(undefined);
		let ad:number
		ad = this.retrouver_la_mesh_dans(this.graduations_grandes,grad.id)
		if(ad>=0)
		{
			return(this.valeur_graduations_grandes[ad])
		}
		ad=this.retrouver_la_mesh_dans(this.graduations_moyennes,grad.id)
		if(ad>=0)
		{
			return(this.valeur_graduations_moyennes[ad])
		}
		ad=this.retrouver_la_mesh_dans(this.graduations_petites,grad.id)
		if(ad>=0)
		{
			return(this.valeur_graduations_petites[ad])
		}
		ad=this.retrouver_la_mesh_dans(this.trans_graduations_moyennes,grad.id)
		if(ad>=0)
		{
			return(this.valeur_trans_graduations_moyennes[ad])
		}
		ad=this.retrouver_la_mesh_dans(this.trans_graduations_petites,grad.id)
		if(ad>=0)
		{
			return(this.valeur_trans_graduations_petites[ad])
		}
		/*let etiquettes_cliquee:PickingInfo[]=pointerInfo.pickInfo.ray.intersectsMeshes(this.graduations_grandes_etiquettes)
		if(etiquettes_cliquee.length>0)
		{
			let gg:string=etiquettes_cliquee[0].pickedMesh.id.substring(17,etiquettes_cliquee[0].pickedMesh.id.length-5)
			let vv:number=this.valeur_de_graduation[parseInt(gg)]

			console.log("mesh : ",etiquettes_cliquee[0].pickedMesh.id)
			console.log("--> expression litherale : ",gg)
			console.log("----> valeur : ",vv)
			return(vv)
		}
		else
		{
			let etiquettes_cliquee_trans:PickingInfo[]=pointerInfo.pickInfo.ray.intersectsMeshes(this.trans_graduations_grandes_etiquettes)
			if(etiquettes_cliquee_trans.length>0)
			{
				console.log("mesh trans: ",etiquettes_cliquee_trans[0].pickedMesh.id)

				let gg:string=etiquettes_cliquee_trans[0].pickedMesh.id.substring(23,etiquettes_cliquee_trans[0].pickedMesh.id.length-5)
				let vv:number=this.valeur_de_graduation_trans[parseInt(gg)]

				console.log("mesh : ",etiquettes_cliquee_trans[0].pickedMesh.id)
				console.log("--> expression litherale : ",gg)
				console.log("----> valeur : ",vv)
				return(vv)
			}
			else
			{
				let graduation_cliquee_grande:PickingInfo[]=pointerInfo.pickInfo.ray.intersectsMeshes(this.graduations_grandes);
				let graduation_cliquee_moyenne:PickingInfo[]=pointerInfo.pickInfo.ray.intersectsMeshes(this.graduations_moyennes);
				let graduation_cliquee_petite:PickingInfo[]=pointerInfo.pickInfo.ray.intersectsMeshes(this.graduations_petites);
				if(graduation_cliquee_grande.length>0)
				{
					console.log("mesh gradu: ",graduation_cliquee_grande[0].pickedMesh.id)
					let gg:string=graduation_cliquee_grande[0].pickedMesh.id.substring(17)
					let vv:number=this.valeur_de_graduation[parseInt(gg)]

					console.log("mesh : ",graduation_cliquee_grande[0].pickedMesh.id)
					console.log("--> expression litherale : ",gg)
					console.log("----> valeur : ",vv)
					return(vv)
				}
				else if(graduation_cliquee_moyenne.length>0)
				{
					console.log("mesh gradu: ",graduation_cliquee_moyenne[0].pickedMesh.id)

					let gg:string=graduation_cliquee_moyenne[0].pickedMesh.id.substring(18)
					let vv:number=this.valeur_de_graduation[(this.nb_graduations_maximal/10+2)+parseInt(gg)]

					console.log("mesh : ",graduation_cliquee_moyenne[0].pickedMesh.id)
					console.log("--> expression litherale : ",gg)
					console.log("----> valeur : ",vv)
					return(vv)
				}
				else if(graduation_cliquee_petite.length>0)
				{
					console.log("mesh gradu: ",graduation_cliquee_petite[0].pickedMesh.id)

					let gg:string=graduation_cliquee_petite[0].pickedMesh.id.substring(17)
					let vv:number=this.valeur_de_graduation[(this.nb_graduations_maximal/10+2)+(this.nb_graduations_maximal/10+2)+parseInt(gg)]

					console.log("mesh : ",graduation_cliquee_petite[0].pickedMesh.id)
					console.log("--> expression litherale : ",gg)
					console.log("----> valeur : ",vv)
					return(vv)
				}
			}
		}*/
		return(undefined)			
	}

	demande_retirer_outil():void
	{
		console.log("tentative de changement de curseur")
		this.attache_curseur.source = "assets/gabarits/droite_graduee/curseur_rien.png"
		this.type_doutil = Outil.Rien
		this.scene.defaultCursor = 'default'
		if(this.activation_du_segment)
		{
			this.segment.material.alpha=0.0
		}
	}

	async demande_outil_joker()
	{
		console.log("tentative de changement de curseur")
		if(this.nb_joker>0)
		{
			this.scene.defaultCursor = 'none'
			this.attache_curseur.source = "assets/gabarits/droite_graduee/Curseur-Joker.webp"
			if(this.activation_du_segment)
			{
				this.segment.material.alpha=0.0
			}
			this.type_doutil = Outil.Joker
		}
		else
		{
			await this.envoyer_instruction("Désolé, mais tu n'as plus de joker à placer.", true)
			this.attache_curseur.source = "assets/gabarits/droite_graduee/curseur_rien.png"
			this.type_doutil = Outil.Rien
			this.scene.defaultCursor = 'default'
			if(this.activation_du_segment)
			{
				this.segment.material.alpha=0.0
			}
		}
	}

	async demande_outil_placeur()
	{
		console.log("tentative de changement de curseur")
		if(this.type_epreuve==Epreuve.Placer && this.tentatives>0)
		{
			if(this.activation_du_segment)
			{
				this.segment.material.alpha=1.0
				this.scene.defaultCursor = 'none'
				this.attache_curseur.source = "assets/gabarits/droite_graduee/curseur_rien.png"
			}
			else
			{
				this.scene.defaultCursor = 'none'
				this.attache_curseur.source = "assets/gabarits/droite_graduee/Curseur-Classique.webp"
			}
			this.type_doutil = Outil.Selection
		}
		else
		{
			await this.envoyer_instruction("Désolé, mais tu n'as plus de joker à placer.", true)
			this.attache_curseur.source = "assets/gabarits/droite_graduee/curseur_rien.png"
			this.type_doutil = Outil.Rien
			this.scene.defaultCursor = 'default'
			if(this.activation_du_segment)
			{
				this.segment.material.alpha=0.0
			}
		}
	}

	creer_attache_curseurs():void
	{
		this.attache_curseur = new GUI.Image("cursor","assets/gabarits/droite_graduee/curseur_rien.png")
		this.attache_curseur.width = "50px";
		this.attache_curseur.height = "50px";
		this.attache_curseur.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
		this.attache_curseur.verticalAlignment   = GUI.Control.VERTICAL_ALIGNMENT_TOP;
		this.attache_curseur.isHitTestVisible = false;
		this.gui.addControl(this.attache_curseur);
	}

	creer_menu(): void
	{
		this.gui = AdvancedDynamicTexture.CreateFullscreenUI("Menu", true, this.scene);
		// boutons zoom
		const panel_zoom = new Rectangle();
		panel_zoom.width = "400px";
		panel_zoom.height = "110px";
  		panel_zoom.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
  		panel_zoom.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
		panel_zoom.top = "-48px"
		panel_zoom.color = "transparent";
		panel_zoom.thickness = 0;

  		this.gui.addControl(panel_zoom);

		this.zoomInBtn = Button.CreateImageOnlyButton("zoomIn","assets/gabarits/droite_graduee/Zoom+-Start.webp");
		this.zoomInBtn.onPointerEnterObservable.add(() => { this.zoomInBtn.image!.source = "assets/gabarits/droite_graduee/Zoom+-Hover.webp";});
		this.zoomInBtn.onPointerOutObservable.add(() => { this.zoomInBtn.image!.source = "assets/gabarits/droite_graduee/Zoom+-Start.webp";});
		this.zoomInBtn.onPointerUpObservable.add(() => {  this.homotetie_graduations(1.0, 0.0);});
		this.zoomInBtn.height = "110px";
		this.zoomInBtn.width = "200px";
		this.zoomInBtn.thickness = 0;
		this.zoomInBtn.background = "transparent";
		this.zoomInBtn.left = "105px";

		this.zoomOutBtn = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/Zoom--Start.webp");
		this.zoomOutBtn.onPointerEnterObservable.add(() => { this.zoomOutBtn.image!.source = "assets/gabarits/droite_graduee/Zoom--Hover.webp";});
		this.zoomOutBtn.onPointerOutObservable.add(() => { this.zoomOutBtn.image!.source = "assets/gabarits/droite_graduee/Zoom--Start.webp";});
		this.zoomOutBtn.onPointerUpObservable.add(() => { this.homotetie_graduations(-1.0, 0.0);});
		this.zoomOutBtn.height = "110px";
		this.zoomOutBtn.width = "200px";
		this.zoomOutBtn.thickness = 0;
		this.zoomOutBtn.background = "transparent";
		this.zoomOutBtn.left = "-105px";

		panel_zoom.addControl(this.zoomInBtn);
		panel_zoom.addControl(this.zoomOutBtn);
		// bouton fleches
		this.fleche_gauche = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/IconeFlecheStart-DroiteGradue.webp");
		this.fleche_gauche.onPointerEnterObservable.add(() => { this.fleche_gauche.image!.source = "assets/gabarits/droite_graduee/IconeFlecheHover-DroiteGradue.webp";});
		this.fleche_gauche.onPointerOutObservable.add(() => { this.fleche_gauche.image!.source = "assets/gabarits/droite_graduee/IconeFlecheStart-DroiteGradue.webp";});
		this.fleche_gauche.onPointerUpObservable.add(() => { this.translation_graduations(this.sensibilite_translation_bouton);});
		this.fleche_gauche.height = "101px";
		this.fleche_gauche.width = "63px";
		this.fleche_gauche.thickness = 0;
		this.fleche_gauche.background = "transparent";
		this.fleche_gauche.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  		this.fleche_gauche.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
		const position = 10 * this.canvas.clientWidth / 100 - 100;
		this.fleche_gauche.left= position + "px";
		//this.fleche_gauche.top="95px"
		this.gui.addControl(this.fleche_gauche)

		this.fleche_droite = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/IconeFlecheDroiteStart-DroiteGradue.webp");
		this.fleche_droite.onPointerEnterObservable.add(() => { this.fleche_droite.image!.source = "assets/gabarits/droite_graduee/IconeFlecheDroiteHover-DroiteGradue.webp";});
		this.fleche_droite.onPointerOutObservable.add(() => { this.fleche_droite.image!.source = "assets/gabarits/droite_graduee/IconeFlecheDroiteStart-DroiteGradue.webp";});
		this.fleche_droite.onPointerUpObservable.add(() => { this.translation_graduations(-this.sensibilite_translation_bouton);});
		this.fleche_droite.height = "101px";
		this.fleche_droite.width = "63px";
		this.fleche_droite.thickness = 0;
		this.fleche_droite.background = "transparent";
		this.fleche_droite.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
  		this.fleche_droite.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
		this.fleche_droite.left= -position + "px"
		//this.fleche_droite.top="95px"
		this.gui.addControl(this.fleche_droite)
		// menu colone

		// etiquette instruction

		// menu tentatives
		this.bouton_tentative = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/CTAfleche-Start.webp");
		this.bouton_tentative.onPointerEnterObservable.add(() => { this.bouton_tentative.image!.source = "assets/gabarits/droite_graduee/CTAfleche-Hover.webp";});
		this.bouton_tentative.onPointerOutObservable.add(() => { this.bouton_tentative.image!.source = "assets/gabarits/droite_graduee/CTAfleche-Start.webp";});
		this.bouton_tentative.onPointerUpObservable.add(() => {  this.demande_outil_placeur();});
		this.bouton_tentative.height = "75px";
		this.bouton_tentative.width = "75px";
		this.bouton_tentative.thickness = 0;
		this.bouton_tentative.background = "transparent";
		this.bouton_tentative.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
  		this.bouton_tentative.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
		this.bouton_tentative.left="-50px"
		this.bouton_tentative.top="200px"
		this.gui.addControl(this.bouton_tentative)

		this.vignette_tentative = new TextBlock();
        this.vignette_tentative.width = "100px";
        this.vignette_tentative.height = "40px";
        this.vignette_tentative.text = "tentatives";
        this.vignette_tentative.color = "blue";
		this.vignette_tentative.fontWeight = "bold"
		this.vignette_tentative.fontFamily = "Poppins";
		this.vignette_tentative.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_RIGHT
		this.vignette_tentative.verticalAlignment=Control.VERTICAL_ALIGNMENT_TOP
		this.vignette_tentative.isHitTestVisible = false;
		this.vignette_tentative.left = "-40px"
		this.vignette_tentative.top = "235px"
        this.gui.addControl(this.vignette_tentative);
		// menus fuels
		this.bouton_translation = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/fuel_trans.png");
		this.bouton_translation.alpha = 0;

		this.bouton_translation.height = "75px";
		this.bouton_translation.width = "75px";
		this.bouton_translation.thickness = 0;
		this.bouton_translation.background = "transparent";
		this.bouton_translation.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  		this.bouton_translation.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
		this.bouton_translation.left="50px"
		this.bouton_translation.top="-50px"
		this.gui.addControl(this.bouton_translation)

		this.vignette_translation = new TextBlock();
		this.vignette_translation.alpha = 0;

        this.vignette_translation.width = "100px";
        this.vignette_translation.height = "40px";
        this.vignette_translation.text = "translation";
        this.vignette_translation.color = "black";
		this.vignette_translation.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_LEFT
		this.vignette_translation.verticalAlignment=Control.VERTICAL_ALIGNMENT_BOTTOM
		this.vignette_translation.left = "30px"
		this.vignette_translation.top = "-45px"
        this.gui.addControl(this.vignette_translation);

		this.bouton_homotethie = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/fuel_zoom.png");
		this.bouton_homotethie.alpha = 0;
		this.bouton_homotethie.height = "75px";
		this.bouton_homotethie.width = "75px";
		this.bouton_homotethie.thickness = 0;
		this.bouton_homotethie.background = "transparent";
		this.bouton_homotethie.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  		this.bouton_homotethie.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
		this.bouton_homotethie.left="150px"
		this.bouton_homotethie.top="-50px"
		this.gui.addControl(this.bouton_homotethie)

		this.vignette_homotethie = new TextBlock();
		this.vignette_homotethie.alpha = 0;

        this.vignette_homotethie.width = "100px";
        this.vignette_homotethie.height = "40px";
        this.vignette_homotethie.text = "homothetie";
        this.vignette_homotethie.color = "black";
		this.vignette_homotethie.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_LEFT
		this.vignette_homotethie.verticalAlignment=Control.VERTICAL_ALIGNMENT_BOTTOM
		this.vignette_homotethie.left = "130px"
		this.vignette_homotethie.top = "-45px"
        this.gui.addControl(this.vignette_homotethie);
		// timer
		this.bouton_compte_a_rebour = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/Timmer.webp");
		this.bouton_compte_a_rebour.alpha = 0;

		this.bouton_compte_a_rebour.height = "75px";
		this.bouton_compte_a_rebour.width = "75px";
		this.bouton_compte_a_rebour.thickness = 0;
		this.bouton_compte_a_rebour.background = "transparent";
		this.bouton_compte_a_rebour.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
  		this.bouton_compte_a_rebour.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
		this.bouton_compte_a_rebour.left="-50px"
		this.bouton_compte_a_rebour.top="100px"
		this.gui.addControl(this.bouton_compte_a_rebour)

		this.vignette_compte_a_rebour = new TextBlock();
		this.vignette_compte_a_rebour.alpha = 0;

        this.vignette_compte_a_rebour.width = "100px";
        this.vignette_compte_a_rebour.height = "40px";
        this.vignette_compte_a_rebour.text = "timer";
        this.vignette_compte_a_rebour.color = "white";
		this.vignette_compte_a_rebour.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_RIGHT
		this.vignette_compte_a_rebour.verticalAlignment=Control.VERTICAL_ALIGNMENT_TOP
		this.vignette_compte_a_rebour.fontWeight = "bold"
		this.vignette_compte_a_rebour.isHitTestVisible = false;
		this.vignette_compte_a_rebour.left = "-35px"
		this.vignette_compte_a_rebour.top = "120px"
        this.gui.addControl(this.vignette_compte_a_rebour);
		// joker
		this.bouton_joker = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/JokerA-Start.webp");
		this.bouton_joker.onPointerEnterObservable.add(() => { if(this.bouton_joker.image.source == "assets/gabarits/droite_graduee/JokerA-Blocked.webp")return; this.bouton_joker.image!.source = "assets/gabarits/droite_graduee/JokerA-Hover.webp";});
		this.bouton_joker.onPointerOutObservable.add(() => { if(this.bouton_joker.image.source == "assets/gabarits/droite_graduee/JokerA-Blocked.webp")return; this.bouton_joker.image!.source = "assets/gabarits/droite_graduee/JokerA-Start.webp";});
		this.bouton_joker.onPointerUpObservable.add(() => {  this.demande_outil_joker();});
		this.bouton_joker.height = "75px";
		this.bouton_joker.width = "75px";
		this.bouton_joker.thickness = 0;
		this.bouton_joker.background = "transparent";
		this.bouton_joker.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
  		this.bouton_joker.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
		this.bouton_joker.left="-50px"
		this.bouton_joker.top="300px"
		this.gui.addControl(this.bouton_joker)

		this.vignette_joker = new TextBlock();
        this.vignette_joker.width = "50px";
        this.vignette_joker.height = "20px";
        this.vignette_joker.text = "joker";
        this.vignette_joker.color = "black";
		this.vignette_joker.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_RIGHT
		this.vignette_joker.verticalAlignment=Control.VERTICAL_ALIGNMENT_TOP
		this.vignette_joker.left = "-62px"
		this.vignette_joker.top = "350px"
		this.vignette_joker.outlineWidth = 0;
		this.vignette_joker.color = "blue"
		this.vignette_joker.fontWeight = "bold"
		this.vignette_joker.fontFamily = "Poppins";
		this.vignette_joker.isHitTestVisible = false;
        this.gui.addControl(this.vignette_joker);
		
		// instruction
		const bgk = new GUI.Image("bg", "assets/gabarits/droite_graduee/fenetre_rose.png");
		bgk.stretch = GUI.Image.STRETCH_FILL;
		this.fenetre_instruction = new Rectangle();
		this.fenetre_instruction.width = "650px";
		this.fenetre_instruction.height = "175px";
		this.fenetre_instruction.top = "-200px"
		this.fenetre_instruction.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_CENTER
		this.fenetre_instruction.verticalAlignment=Control.VERTICAL_ALIGNMENT_BOTTOM
		this.fenetre_instruction.thickness = 0;
		this.fenetre_instruction.addControl(bgk);
		this.gui.addControl(this.fenetre_instruction);

		this.instruction= new GUI.TextBlock();
		this.instruction.top = "-270px"
		this.instruction.width = '500px';
		this.instruction.height = '100px';
		this.instruction.color = 'black';
		this.instruction.textWrapping = true;
		//this.instruction.alpha = 0;
		this.instruction.fontSize = 24;
		this.instruction.isHitTestVisible = false;
		this.instruction.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_CENTER
		this.instruction.verticalAlignment=Control.VERTICAL_ALIGNMENT_BOTTOM
		this.gui.addControl(this.instruction);

		this.bouton_instruction = Button.CreateImageOnlyButton("zoomOut","assets/gabarits/droite_graduee/bouton_fenetre_rose.png");
		this.bouton_instruction.onPointerUpObservable.add(() => {  this.instruction.alpha=0; this.bouton_instruction.alpha=0; this.fenetre_instruction.alpha=0; this.bouton_instruction.isVisible = false;});
		this.bouton_instruction.onPointerEnterObservable.add(() => { this.bouton_instruction.image!.source = "assets/gabarits/droite_graduee/bouton_fenetre_rose_hover.png";});
		this.bouton_instruction.onPointerOutObservable.add(() => { this.bouton_instruction.image!.source = "assets/gabarits/droite_graduee/bouton_fenetre_rose.png";});
		this.bouton_instruction.height = "62px";
		this.bouton_instruction.width = "66px";
		this.bouton_instruction.thickness = 0;
		this.bouton_instruction.background = "transparent";
		this.bouton_instruction.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
  		this.bouton_instruction.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
		this.bouton_instruction.left="296px" 
		this.bouton_instruction.top="-204px"
		this.gui.addControl(this.bouton_instruction)
		this.instruction.alpha=0; this.bouton_instruction.alpha=0; this.fenetre_instruction.alpha=0; this.bouton_instruction.isVisible = false;


		this.creer_attache_curseurs()
	}

	afficher_paneau_de_confirmation(scene:Scene, value:number, onConfirm?: (value: number) => void) 
	{

		this.page.award = "validation_droitegraduee";
		this.page.eventMessage.next();

		this.page.validationSubject = new Subject<boolean>();
		this.page.validationSubject.subscribe(async result => {
			console.log(result);
			this.page.award = null;
			if(result){
				onConfirm?.(value);
				this.remetre_graduation_en_normale(value);
				// panel.dispose();
			} else {
				this.page.droiteGradueeExercices.readConsigne();
				this.remetre_graduation_en_normale(value);
			}
		});
		/*const gui = AdvancedDynamicTexture.CreateFullscreenUI("UI");

		const panel = new Rectangle();
		panel.width = "220px";
		panel.height = "140px";
		panel.top = "200px"
		panel.cornerRadius = 12;
		panel.color = "white";
		panel.thickness = 2;
		panel.background = "#2c2c2c";
		gui.addControl(panel);

		const stack = new StackPanel();
		panel.addControl(stack);

		const button = Button.CreateSimpleButton("confirm", "Confirmer");
		button.height = "40px";
		button.color = "white";
		button.background = "#4CAF50";
		button.onPointerUpObservable.add(() => {
			onConfirm?.(value);
			this.remetre_graduation_en_normale(value);
			panel.dispose();
		});

		const cancelBtn = Button.CreateSimpleButton("cancel", "Annuler");
    	cancelBtn.height = "40px";
    	cancelBtn.color = "white";
    	cancelBtn.background = "#F44336";
    	cancelBtn.onPointerUpObservable.add(() => {
			this.remetre_graduation_en_normale(value);
        	panel.dispose();
    	});

		stack.addControl(button);
		stack.addControl(cancelBtn);

		return panel;*/
	}

	action_selection_valeur(valeur:number):void
	{
		this.mettre_graduation_en_selection(valeur);
		this.afficher_paneau_de_confirmation(this.scene,valeur,(v:number) => {this.tentative_placer_une_valeur(v)})
	}

	ajouter_une_etiquette_specifique(v:number,s:string):void
	{
		this.etiquettes_joker.push({v: v,s: s})
		this.nb_joker--;
		if(this.nb_joker<=0)this.bouton_joker.image!.source = "assets/gabarits/droite_graduee/JokerA-Blocked.webp";
		this.mettre_a_jour_vignettes()
		this.demande_retirer_outil()
		this.afficher_graduations_entre_deux_valeurs(1.0)
		this.mettre_a_jour_vignettes()
	}

	proposer_un_joker(valeur:number):void
	{
		const panel = new Rectangle();
		panel.width = "200px";
		panel.height = "50px";
		panel.cornerRadius = 12;
		panel.color = "white";
		panel.thickness = 2;
		panel.background = "#2c2c2c";
		this.gui.addControl(panel);

		this.vignette_etiquette_perso=new GUI.InputTextArea();
		this.vignette_etiquette_perso.left = "-25px"
		this.vignette_etiquette_perso.width = '150px';
		this.vignette_etiquette_perso.color = 'white';
		this.vignette_etiquette_perso.background = 'black';
		this.vignette_etiquette_perso.placeholderText = 'Écris ici...';
		panel.addControl(this.vignette_etiquette_perso)

		this.valider_etiquette_perso=Button.CreateSimpleButton("ok_et_perso", "Ok");
		this.valider_etiquette_perso.left="75px"
    	this.valider_etiquette_perso.height = "50px";
		this.valider_etiquette_perso.width = "50px";
    	this.valider_etiquette_perso.color = "white";
    	this.valider_etiquette_perso.background = "#F44336";
    	this.valider_etiquette_perso.onPointerUpObservable.add(() => {
			this.ajouter_une_etiquette_specifique(valeur,this.vignette_etiquette_perso.text);
        	panel.dispose();
    	});
		panel.addControl(this.valider_etiquette_perso);
	}

	creer_interface_de_saisie_de_reponse()
	{
		const panel = new Rectangle();
		panel.width = "200px";
		panel.height = "50px";
		panel.cornerRadius = 12;
		panel.color = "white";
		panel.thickness = 2;
		panel.background = "#2c2c2c";
		panel.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_CENTER
		panel.verticalAlignment=Control.VERTICAL_ALIGNMENT_TOP
		panel.top = "202px"
		this.gui.addControl(panel);

		this.vignette_reponse=new GUI.InputTextArea();
		this.vignette_reponse.left = "-25px"
		this.vignette_reponse.width = '150px';
		this.vignette_reponse.color = 'white';
		this.vignette_reponse.background = 'black';
		this.vignette_reponse.placeholderText = 'Écris ici...';
		panel.addControl(this.vignette_reponse)

		this.valider_reponse=Button.CreateSimpleButton("ok_et_perso", "Ok");
		this.valider_reponse.left="75px"
    	this.valider_reponse.height = "50px";
		this.valider_reponse.width = "50px";
    	this.valider_reponse.color = "white";
    	this.valider_reponse.background = "#F44336";
    	this.valider_reponse.onPointerUpObservable.add(() => {
			this.proposer_une_reponse(this.vignette_reponse.text)
        	panel.dispose();
    	});
		panel.addControl(this.valider_reponse);
	}

	async proposer_une_reponse(reponse:string)
	{
		this.derniere_valeur_choisi = Number(reponse)
		if(Number(reponse)==this.valeur_a_trouver)
		{
			await this.envoyer_instruction("Bravo! Tu as gagné !", true)
			this.demande_retirer_outil();
			this.gagnee()
		}
		else
		{
			this.tentatives--;
			this.mettre_a_jour_vignettes()
			if(this.tentatives<=0)
			{
				await this.envoyer_instruction("Dommage, tu t'es encore trompé et tu n'as plus de tentatives.", true)
				this.demande_retirer_outil();
				this.perdue()
			}
			else
			{
				await this.envoyer_instruction("Non, ce n'est pas ça, essaye encore.", true)
				this.waitUserAnswer.next({ success: false, response: this.derniere_valeur_choisi });
				this.creer_interface_de_saisie_de_reponse()
			}
		}
		this.mettre_a_jour_vignettes()
	}

	mettre_graduation_en_hoover(valeur:number)
	{
		this.graduation_hover.push(valeur)
	}

	mettre_graduation_en_selection(valeur:number)
	{
		this.graduation_selectionne.push(valeur)
	}

	remetre_graduation_en_normale(valeur:number)
	{
		this.graduation_hover = this.graduation_hover.filter(function(f) 
		{
  			return(f!=valeur)
		})
		this.graduation_selectionne = this.graduation_selectionne.filter(function(f) 
		{
  			return(f!=valeur)
		})
	}

	async tentative_placer_une_valeur(valeur:number)
	{
		this.derniere_valeur_choisi = valeur
		if(Math.abs(valeur-this.valeur_a_trouver)<=this.ecart_max_tolere)
		{
			if(valeur==this.valeur_a_trouver){
				await this.envoyer_instruction("Bravo, c'est la bonne valeur.", true)
			}
			else {
				await this.envoyer_instruction("Bravo, effectivement "+(new String(Number(valeur).toFixed(2)).replace("\.",","))+" est assez proche de "+this.valeur_a_trouver.toString().replace("\.",",")+". Tu as gagné !", true)
			}
			this.demande_retirer_outil();
			this.gagnee()
		}
		else
		{
			let gg:string = "Non, ce n'est pas ça. Tu as choisi : "+valeur.toString().replace("\.",",");
			this.tentatives--;
			if(this.tentatives<=0)
			{
				this.bouton_tentative.image!.source = "assets/gabarits/droite_graduee/CTAfleche-Blocked.webp";
				gg += ". Tu as perdu !"
				this.demande_retirer_outil();
				await this.envoyer_instruction(gg, true)
				this.perdue()
			}
			else
			{
				await this.envoyer_instruction(gg, true)
				this.waitUserAnswer.next({ success: false, response: this.derniere_valeur_choisi });
				gg+= ". Il te reste encore "+this.tentatives.toString() + " tentatives."
			}
		}
		this.mettre_a_jour_vignettes()
	}

	gerer_le_hover_des_graduations(pointerInfo:PointerInfo)
	{
		let lehov:number=this.trouver_valeur_du_clique(pointerInfo)
		this.graduation_hover=[]
		if(lehov!=undefined)
		{
			this.mettre_graduation_en_hoover(lehov)
		}
	}
	
	addMouseWheelPinchEvent():void
	{
		this.scene.onPointerObservable.add((pointerInfo:PointerInfo,eventstat:EventState) => 
			{
				// prevent all default (native chrome pinch zoom)
				if(pointerInfo.event instanceof PointerEvent)
				{
					pointerInfo.event.preventDefault();
				}
				switch (pointerInfo.type) 
				{
					case PointerEventTypes.POINTERWHEEL:
						if(pointerInfo.pickInfo.ray.intersectsMesh(this.bg_blanc).hit)
						{
							this.homotetie_graduations((pointerInfo.event as any).wheelDelta,pointerInfo.pickInfo.ray.origin.x);
						}
						break;
					case PointerEventTypes.POINTERDOWN:
					{//console.log("clique")
						if (pointerInfo.event.button === 0)
						{
							if(pointerInfo.pickInfo.ray.intersectsMesh(this.bg_blanc).hit)
							{
								this.drag_position_active=1
								this.mouse_px=pointerInfo.pickInfo.ray.origin.x
								//
								if(pointerInfo.pickInfo.ray.origin.y > -0.1 && pointerInfo.pickInfo.ray.origin.y < 0.1){
									if(this.type_doutil==Outil.Selection && this.activation_du_segment)
									{
										let valeur:number=(this.segment.position.x-this.position_centre_geo)/this.resolution_geo*this.resolution_valeur+this.position_centre_valeur;
										this.action_selection_valeur(valeur);
									}
									else
									{
										let valeur:number=this.trouver_valeur_du_clique(pointerInfo)
										console.log("--------------- SELECT -------------- : ",valeur)
										if(valeur!=undefined)
										{
											if(this.type_doutil==Outil.Selection)this.action_selection_valeur(valeur);
											else if(this.type_doutil==Outil.Joker)this.proposer_un_joker(valeur)
											this.afficher_graduations_entre_deux_valeurs(1.0)
										}
									}
								}
							}
							else
							{
								console.log(this.variables)
								//this.centrer_sur_une_valeur(318.2)
							}
						}
						break;
					}
					case PointerEventTypes.POINTERUP:
					{
						if (pointerInfo.event.button === 2)
						{
							this.demande_retirer_outil()
						}
						console.log("lever",pointerInfo,eventstat)
						this.drag_position_active=0
						break;
					}
					case PointerEventTypes.POINTERMOVE:
					{//console.log("bouge (event) : ",pointerInfo.pickInfo.ray.origin.x)
						// console.log(pointerInfo.pickInfo.ray.origin.y)
						if((this.type_doutil==Outil.Selection && !this.activation_du_segment)||this.type_doutil==Outil.Joker){
							this.gerer_le_hover_des_graduations(pointerInfo)
						}
						if(pointerInfo.pickInfo.ray.intersectsMesh(this.bg_blanc).hit && this.drag_position_active==1)
						{
							this.mouse_dx=pointerInfo.pickInfo.ray.origin.x-this.mouse_px
							//console.log("bouge (dx): ",this.mouse_dx,this.mouse_px,pointerInfo.pickInfo.ray.origin.x)
							this.mouse_px=pointerInfo.pickInfo.ray.origin.x
							this.translation_graduations(this.mouse_dx*this.sensibilite_translation)
						}
						else this.drag_position_active=0;
						if(this.activation_du_segment)
						{
							this.segment.position.x=(pointerInfo.event.clientX/this.canvas.clientWidth)*this.longueur_scene-0.5*this.longueur_scene;
							this.segment.scaling.x = (this.ecart_max_tolere*2)*this.resolution_geo/this.resolution_valeur;
						}
						this.position_x_curseur_axe=(pointerInfo.event.clientX/this.canvas.clientWidth)*this.longueur_scene-0.5*this.longueur_scene;
						this.attache_curseur.left = pointerInfo.event.clientX-25 + "px";
    					this.attache_curseur.top  = pointerInfo.event.clientY + "px";
						this.afficher_graduations_entre_deux_valeurs(1.0)
						//this.mettre_graduation("grand",this.position_x_curseur_axe,0.0,1.0,0.0)
						break;
					}
				}
			}
		);
		if (this.camera instanceof ArcRotateCamera) 
		{
			// hack reduce delay for pinch zoom or pan choice useful when only one activated to remove the delay
			
			(this.camera as ArcRotateCamera).pinchToPanMaxDistance = 0;
			const pointers = (this.camera as ArcRotateCamera).inputs.attached.pointers as ArcRotateCameraPointersInput;
			pointers.onMultiTouch = (
						pointA: PointerTouch,
						pointB: PointerTouch,
						previousPinchSquaredDistance: number,
						pinchSquaredDistance: number,
						previousMultiTouchPanPosition: PointerTouch,
						multiTouchPanPosition: PointerTouch
			) => {
					this.homotetie_graduations(pinchSquaredDistance - previousPinchSquaredDistance,previousMultiTouchPanPosition.x);
				};
		}
	}

    faire_couleurs(): void 
    {
        var blacke:StandardMaterial = new StandardMaterial("black", this.scene);
        blacke.diffuseColor = new Color3(1,1,1);
        blacke.specularColor = new Color3(0., 0., 0.);
		this.couleur_graduation_defaut = new StandardMaterial("couleur_graduation_defaut", this.scene);
        this.couleur_graduation_defaut.diffuseColor = new Color3(1,1,1);
        this.couleur_graduation_defaut.specularColor = new Color3(0., 0., 0.);
		this.couleur_graduation_hover = new StandardMaterial("couleur_graduation_hover", this.scene);
        this.couleur_graduation_hover.diffuseColor = new Color3(1,1,0);
        this.couleur_graduation_hover.specularColor = new Color3(0., 0., 0.);
		this.couleur_graduation_select = new StandardMaterial("couleur_graduation_select", this.scene);
        this.couleur_graduation_select.diffuseColor = new Color3(1,0.5,0);
        this.couleur_graduation_select.specularColor = new Color3(0., 0., 0.);
    }

    ecrir_text(idtext:string,x:number,y:number,z:number,texte:string,couleur:string="white"):Mesh
    {
		var textext:DynamicTexture = new DynamicTexture("dtexture_"+idtext,{ width: 150, height: 50 }, this.scene);
		textext.update();
		textext.drawText(texte,null,null,`30px solid Arial`,couleur,null);
		textext.update();
		var cube:Mesh = MeshBuilder.CreatePlane(idtext,{height: this.hauteur_etiquette,width: this.longueur_etiquette},this.scene)
		cube.position.x = x + this.x
		cube.position.y = y + this.y
		cube.position.z = z + this.z
		const material:StandardMaterial = new StandardMaterial("mat_"+idtext, this.scene);
		material.diffuseTexture = textext;
		material.diffuseTexture.hasAlpha = true;
		material.useAlphaFromDiffuseTexture = true;
		material.transparencyMode = BABYLON.Material.MATERIAL_ALPHABLEND;
		material.roughness = 1.0
		material.alpha = 0.0
		cube.material = material;
		(cube.material as StandardMaterial).specularColor = new BABYLON.Color3(0, 0, 0);
		cube.layerMask=this.camera.layerMask
		return(cube)
    }

	supprimer_text(idtext: string): void 
	{
		var meshe = this.scene.getMeshByName(idtext);
		meshe?.dispose();
		var mat:Material=this.scene.getMaterialByName("mat_"+idtext);
		(mat as StandardMaterial).diffuseTexture.dispose()
		mat?.dispose();
	}

	faire_segment():void
	{
		this.segment = MeshBuilder.CreatePlane("axe", {height: this.epaisseur_segment,width:1.0}, this.scene);
		this.segment.material = this.scene.getMaterialByID("black").clone("mat_segment");
        this.segment.material.alpha = 0.0;
		(this.segment.material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
		this.segment.position.x = this.x
		this.segment.position.y = this.y
		this.segment.position.z = this.z
		this.segment.layerMask=this.camera.layerMask
	}

    faire_axe(): void
    {
		// revoir l affichage
		const canvas = this.canvas;
		const width  = canvas.clientWidth;
		
		const d = Vector3.Distance(this.camera.position, new Vector3(0,0,-1.5));
		const height = 2 * Math.tan(this.camera.fov / 2) * d
		const widthS = height * this.engine.getAspectRatio(this.camera);
		this.longueur_scene = widthS;

		this.longueur_axe_affichee = Math.round(80*widthS) / 100;

        var cylinder:Mesh = MeshBuilder.CreatePlane("axe", {height: this.longueur_axe_affichee,width:0.01}, this.scene);
        cylinder.rotation.z = 3.141592/2.0
		cylinder.position.z = this.z
		cylinder.position.x = this.x
		cylinder.position.y = this.y
        cylinder.material= this.scene.getMaterialByID("black");
        cylinder.layerMask=this.camera.layerMask

		this.main_axe = cylinder;


    }

    faire_graduation(idgrad:string,x:number,taille:number,etiquette:string,opacite:number,largeur:number,nonclicable:boolean=false): Mesh
    {
        //var cylinder:Mesh = MeshBuilder.CreateCylinder("graduation_"+idgrad, {height: 0.05*opacite,diameterTop: taille*opacite,diameterBottom: taille*opacite, tessellation: 8}, this.scene);
        var cylinder:Mesh = MeshBuilder.CreatePlane("graduation_"+idgrad,{width: largeur*opacite, height: taille*opacite},this.scene)
		//cylinder.rotation.z=3.141592/2.0
		cylinder.position.x=x + this.x;
		cylinder.position.y=this.y;
		cylinder.position.z=this.z
        cylinder.material= this.scene.getMaterialByID("black").clone("mat_"+idgrad);
        cylinder.material.alpha = opacite
		cylinder.layerMask=this.camera.layerMask
		cylinder.isPickable = false;
        if(etiquette!="")
		{
			this.ecrir_text("graduation_"+idgrad+"_text",x,taille/2+this.hauteur_etiquette/2.0,0.0,etiquette)
		}
		if(!nonclicable)
		{
			const hitBox = MeshBuilder.CreatePlane("graduation_"+idgrad+"_hitBox",{width: largeur*opacite*this.facteur_de_hitbox, height: taille*opacite*100},this.scene);
			hitBox.material= this.scene.getMaterialByID("black").clone("mat_"+idgrad);
			hitBox.isVisible = false;
			hitBox.isPickable = true;
			hitBox.parent = cylinder;
			//this.graduations.push(idgrad)
		}
		return(cylinder)
    }

	faire_graduation_clonee(idmodel:string,idgrad:string,x:number,etiquette:string): void
    {
        var cylinder= this.scene.getMeshByName(idmodel)?.clone(idgrad, null) as Mesh
		cylinder.position.x=x+this.x
		cylinder.position.y=this.y
		cylinder.position.z=this.z
		cylinder.layerMask=this.camera.layerMask
        if(etiquette!="")
		{
			this.ecrir_text("graduation_"+idgrad+"_text",x,this.hauteur_grande_graduation/2+this.hauteur_etiquette/2.0,-1.0,etiquette)
		}
		this.graduations.push(idgrad)
    }

	suprimer_graduation(idgrad:string): void
	{
		var mesh = this.scene.getMeshByName("graduation_"+idgrad);
		mesh?.dispose();
		var mat=this.scene.getMaterialByID("mat_"+idgrad)
		mat?.dispose()
		if(this.scene.getMeshByName("graduation_"+idgrad+"_text"))
		{
			this.supprimer_text("graduation_"+idgrad+"_text");
		}
		this.graduations.filter(nom => nom !== idgrad)
	}

	changer_transparence_graduation(idgrad:string,alfa:number): void
	{
		var mesh = this.scene.getMeshByName("graduation_"+idgrad);
		if (mesh.material) 
		{
    		mesh.material.alpha = alfa;
		}
	}

	faire_arriere_plan():void
	{
		var plan:Mesh = MeshBuilder.CreatePlane("arriere_plan",{width: 16, height: 10},this.scene)
		plan.layerMask=this.camera.layerMask
		var blacke:StandardMaterial = new StandardMaterial("white", this.scene);
        blacke.diffuseTexture = new Texture("assets/gabarits/droite_graduee/Fond-RegleGradue.jpg", this.scene);
        blacke.specularColor = new Color3(0., 0., 0.);
		blacke.emissiveColor= new Color3(1,1,1);
		plan.material = blacke
		plan.position.x = this.x
		plan.position.y = this.y
		plan.position.z=this.z+0.05
		this.bg_blanc=plan
	}

	supprimer_toute_les_graduations():void
	{
		for(const lid of this.graduations)
			this.suprimer_graduation(lid)
		//while(this.graduations.length>0)this.suprimer_graduation(this.graduations[0])
	}
	
	mise_du_blanc_en_transparence(t:DynamicTexture):void
	{
		const ctx = t.getContext();
		const imageData = ctx.getImageData(0, 0, 150, 50);
		const data = imageData.data;
		for (let i = 0; i < data.length; i += 4) 
		{
  			const r = data[i];
  			const g = data[i + 1];
  			const b = data[i + 2];
  			// Blanc pur
  			if (r === 255 && g === 255 && b === 255)
			{
    			data[i + 3] = 0; // alpha = transparent
  			}
		}
		ctx.putImageData(imageData, 0, 0);
	}

	remplir_texte(t:DynamicTexture,val:number,couleur:string="white",direct:string=""):void
	{
		const ctx = t.getContext();
		ctx.clearRect(0, 0, t.getSize().width, t.getSize().height);
		if(direct!="")
		{
			t.drawText(direct,null,null,`30px solid Arial`,couleur,null);
			return;
		}
		if(this.representation==Representation.Decimale)
		{
			t.drawText((Math.round(val*1000000.0)/1000000.0).toString(),null,null,`30px solid Arial`,couleur,null);
		}
		else if(this.representation==Representation.Fraction)
		{

		}
		else if(this.representation==Representation.Scientifique)
		{
			t.drawText(val.toExponential(),null,null,`30px solid Arial`,couleur,null);
		}
	}

	wait(ms) 
	{
  		return new Promise(resolve => setTimeout(resolve, ms));
	}

	async centrer_sur_une_valeur(valeur:number)
	{
		var prec_sence:number = this.sensibilite_zoom
		this.sensibilite_zoom=this.vitesse_zoom_auto
		var reso:number
		var i:number
		reso=this.resolution_de_valeur(valeur)
		for(i=0;Math.abs(valeur-this.position_centre_valeur)>this.resolution_valeur*2.0 || this.resolution_valeur>reso;i++)
		{
			// observation
			let v:number=this.grad_la_plus_proche_valeur(valeur)
			console.log("reso : "+reso.toString()+"\nv : "+v.toString()+"\nresolution_valeur : ",this.resolution_valeur.toString()+"\nvaleur : "+valeur.toString())
			// translation
			if(v<this.position_centre_valeur)this.translation_graduations(this.vitesse_translation_auto)
			else if(v>this.position_centre_valeur)this.translation_graduations(-this.vitesse_translation_auto)
			// homothetie
			if(Math.abs(v-this.position_centre_valeur)>30*this.resolution_valeur)
			{
				this.homotetie_graduations(1.0,0.0)
			}
			else
			{
				if(this.resolution_valeur>reso)this.homotetie_graduations(-1.0,0.0)
			}
			// attente
			await this.wait(40)
		}
		this.sensibilite_zoom=prec_sence
	}

	mettre_etiquette_specifique(val:number,type:string,posi:number,alpha:number,couleur:string="white",direct:string="")
	{
		this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].position.x=posi+this.x//-0.5*this.longueur_etiquette
		if(type=="grande")this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].position.y=this.y+this.hauteur_grande_graduation/2.0*alpha+this.hauteur_etiquette/2.0*alpha;
		else if(type=="moyenne")this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].position.y=this.y+this.hauteur_moyenne_graduation/2.0*alpha+this.hauteur_etiquette/2.0*alpha;
		else if(type=="petite")this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].position.y=this.y+this.hauteur_petite_graduation/2.0*alpha+this.hauteur_etiquette/2.0*alpha;
		((this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].material as StandardMaterial).diffuseTexture as DynamicTexture).getContext().clearRect(0, 0, 150, 50);
		this.remplir_texte(((this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].material as StandardMaterial).diffuseTexture as DynamicTexture),val,couleur,direct);
		((this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].material as StandardMaterial).diffuseTexture as DynamicTexture).update();
		this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].material.alpha=alpha
		this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].scaling.x = alpha;
		this.graduations_specifiques_etiquettes[this.index_specifiques_etiquette].scaling.y = alpha;
		this.index_specifiques_etiquette++
	}

	letiquette_est_a_representer(val:number,par_defaut:Boolean):Boolean
	{
		let i:number
		if(par_defaut)
		{
			for(i=0;i<this.etiquettes_supprime_bt.length;i++)
			{
				if(this.etiquettes_supprime_bt[i]["t"]=="v")
				{
					if(val==this.etiquettes_supprime_bt[i]["v"])return(false);
				}
				else if(this.etiquettes_supprime_bt[i]["t"]=="r")
				{
					if(val % this.etiquettes_supprime_bt[i]["r"]==0)return(false);
				}
				else if(this.etiquettes_supprime_bt[i]["t"]=="q")
				{
					if(val % this.etiquettes_supprime_bt[i]["r"]==0)
					{
						if(val >= this.etiquettes_supprime_bt[i]["m"])
						{
							if(val <= this.etiquettes_supprime_bt[i]["M"])return(false);
						}
					}
				}
			}
		}
		else
		{
			var gg:boolean=false
			for(i=0;i<this.etiquettes_ajoute_bt.length;i++)
			{
				if(this.etiquettes_ajoute_bt[i]["t"]=="v")
				{
					if(val==this.etiquettes_ajoute_bt[i]["v"]){gg=true;break;}
				}
				else if(this.etiquettes_ajoute_bt[i]["t"]=="r")
				{
					if(val % this.etiquettes_ajoute_bt[i]["r"]==0){gg=true;break;}
				}
				else if(this.etiquettes_ajoute_bt[i]["t"]=="q")
				{
					if(val % this.etiquettes_ajoute_bt[i]["r"]==0)
					{
						if(val >= this.etiquettes_ajoute_bt[i]["m"])
						{
							if(val <= this.etiquettes_ajoute_bt[i]["M"]){gg=true;break;}
						}
					}
				}
			}
			if(gg)
			for(i=0;i<this.etiquettes_supprime_bt.length;i++)
			{
				if(this.etiquettes_supprime_bt[i]["t"]=="v")
				{
					if(val==this.etiquettes_supprime_bt[i]["v"])return(false);
				}
				else if(this.etiquettes_supprime_bt[i]["t"]=="r")
				{
					if(val % this.etiquettes_supprime_bt[i]["r"]==0)return(false);
				}
				else if(this.etiquettes_supprime_bt[i]["t"]=="q")
				{
					if(val % this.etiquettes_supprime_bt[i]["r"]==0)
					{
						if(val >= this.etiquettes_supprime_bt[i]["m"])
						{
							if(val <= this.etiquettes_supprime_bt[i]["M"])return(false);
						}
					}
				}
			}
			return(gg);
		}
		return(par_defaut)
	}

	a_une_etiquette_joker(etiquette:number)
	{
		let i:number
		for(i=0;i<this.etiquettes_joker.length;i++)
		{
			if(this.etiquettes_joker[i]["v"]==etiquette)
			{
				return(true);
			}
		}
		return(false);
	}

	letiquettes_joker(etiquette):string
	{
		let i:number
		for(i=0;i<this.etiquettes_joker.length;i++)
		{
			if(this.etiquettes_joker[i]["v"]==etiquette)
			{
				return(this.etiquettes_joker[i]["s"]);
			}
		}
		return("...");
	}

	la_graduation_est_hover(val:number):boolean
	{
		return(this.graduation_hover.includes(val));
	}

	la_graduation_est_select(val:number):boolean
	{
		return(this.graduation_selectionne.includes(val));
	}

	etiquette_deja_represente(valeur:number):boolean
	{
		let i:number
		for(i=0;i<this.valeur_etiquete.length;i++)
		{
			if(this.valeur_etiquete[i]==valeur)return(true);
		}
		return(false);
	}

	async envoyer_instruction(inst:string, feedback = false)
	{

		await this.page.scenario.readConsigne(inst, null, feedback);
		this.instruction.text=/*this.les_instructions_a_garder+"\n---------------------\n"+*/inst
		//this.ttsService.playTTSEventProtected(inst)
		if(this.instruction.text!="")
		{
			this.instruction.alpha=0; 
			this.bouton_instruction.alpha=0; 
			this.fenetre_instruction.alpha=0; 
			this.bouton_instruction.isHitTestVisible = true; 
			this.bouton_instruction.isVisible = true;
		}
	}

	mettre_graduation(type_graduation:string,x:number,etiquette:number,transparence:number,valeur:number):void
	{
		if(type_graduation=="grande")
		{
			this.graduations_grandes[this.index_grand].position.x=x+this.x;
			this.scene.getMeshById(this.graduations_grandes[this.index_grand].id+"_hitBox").isPickable =true;
			this.valeur_graduations_grandes[this.index_grand]=etiquette;
			if(this.la_graduation_est_hover(etiquette))
			{
				(this.graduations_grandes[this.index_grand].material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
				this.graduations_grandes[this.index_grand].scaling.x=2.0
			}
			else if(this.la_graduation_est_select(etiquette))
			{
				(this.graduations_grandes[this.index_grand].material as StandardMaterial).diffuseColor = (this.couleur_graduation_select as StandardMaterial).diffuseColor
				this.graduations_grandes[this.index_grand].scaling.x=2.0
			}
			else
			{
				(this.graduations_grandes[this.index_grand].material as StandardMaterial).diffuseColor = (this.couleur_graduation_defaut as StandardMaterial).diffuseColor
				this.graduations_grandes[this.index_grand].scaling.x=1.0
			}
			this.graduations_grandes[this.index_grand].material.alpha=transparence;
			if(this.affichage_valeurs_graduations_decimales && this.letiquette_est_a_representer(etiquette,true))
			{
				this.graduations_grandes_etiquettes[this.index_grand].position.x=x+this.x;
				this.graduations_grandes_etiquettes[this.index_grand].material.alpha=transparence;
				if(this.valeur_de_graduation[this.index_grand]!=valeur)
				{
					((this.graduations_grandes_etiquettes[this.index_grand].material as StandardMaterial).diffuseTexture as DynamicTexture).getContext().clearRect(0, 0, 150, 50);
					this.remplir_texte(((this.graduations_grandes_etiquettes[this.index_grand].material as StandardMaterial).diffuseTexture as DynamicTexture),etiquette);
					((this.graduations_grandes_etiquettes[this.index_grand].material as StandardMaterial).diffuseTexture as DynamicTexture).update();
					this.valeur_etiquete.push(etiquette);
				}
			}
			else if(this.letiquette_est_a_representer(etiquette,false))
			{
				this.mettre_etiquette_specifique(etiquette,"grande",x,1.0)
				this.valeur_etiquete.push(etiquette);
			}
			else if(this.a_une_etiquette_joker(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"grande",x,1.0,"yellow",this.letiquettes_joker(etiquette));
				this.valeur_etiquete.push(etiquette);
			}
			this.valeur_de_graduation[this.index_grand]=valeur
			this.index_grand++;
		}
		else if(type_graduation=="moyenne" && this.sub_graduation_affichable)
		{
			this.graduations_moyennes[this.index_moyen].position.x=x+this.x
			this.scene.getMeshById(this.graduations_moyennes[this.index_moyen].id+"_hitBox").isPickable =true;
			this.valeur_graduations_moyennes[this.index_moyen]=etiquette;
			if(this.la_graduation_est_hover(etiquette))
			{
				(this.graduations_moyennes[this.index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
				this.graduations_moyennes[this.index_moyen].scaling.x=2.0
			}
			else if(this.la_graduation_est_select(etiquette))
			{
				(this.graduations_moyennes[this.index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_select as StandardMaterial).diffuseColor
				this.graduations_moyennes[this.index_moyen].scaling.x=2.0
			}
			else
			{
				(this.graduations_moyennes[this.index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_defaut as StandardMaterial).diffuseColor
				this.graduations_moyennes[this.index_moyen].scaling.x=1.0
			}
			this.graduations_moyennes[this.index_moyen].material.alpha=transparence
			if(this.letiquette_est_a_representer(etiquette,false))
			{
				this.mettre_etiquette_specifique(etiquette,"moyenne",x,1.0)
				this.valeur_etiquete.push(etiquette);
			}
			else if(this.a_une_etiquette_joker(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"moyenne",x,1.0,"yellow",this.letiquettes_joker(etiquette));
				this.valeur_etiquete.push(etiquette);
			}
			this.valeur_de_graduation[this.nb_graduations_maximal/10+2+this.index_moyen]=valeur
			this.index_moyen++;
		}
		else if(this.sub_graduation_affichable)
		{
			this.graduations_petites[this.index_petit].position.x=x+this.x
			this.scene.getMeshById(this.graduations_petites[this.index_petit].id+"_hitBox").isPickable =true;
			this.valeur_graduations_petites[this.index_petit]=etiquette;
			if(this.la_graduation_est_hover(etiquette))
			{
				(this.graduations_petites[this.index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
				this.graduations_petites[this.index_petit].scaling.x=2.0
			}
			else if(this.la_graduation_est_select(etiquette))
			{
				(this.graduations_petites[this.index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_select as StandardMaterial).diffuseColor
				this.graduations_petites[this.index_petit].scaling.x=2.0
			}
			else
			{
				(this.graduations_petites[this.index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_defaut as StandardMaterial).diffuseColor
				this.graduations_petites[this.index_petit].scaling.x=1.0
			}
			this.graduations_petites[this.index_petit].material.alpha=transparence
			if(this.letiquette_est_a_representer(etiquette,false))
			{
				this.mettre_etiquette_specifique(etiquette,"petite",x,1.0)
				this.valeur_etiquete.push(etiquette);
			}
			else if(this.a_une_etiquette_joker(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"petite",x,1.0,"yellow",this.letiquettes_joker(etiquette));
				this.valeur_etiquete.push(etiquette);
			}
			this.valeur_de_graduation[(this.nb_graduations_maximal/10+2)+(this.nb_graduations_maximal/10+2)+this.index_petit]=valeur
			this.index_petit++
		}
	}

	mettre_graduation_trans(type_graduation:string,x:number,etiquette:number,transparence:number,valeur:number,hauteur_artificel:number=0):void
	{
		if(!this.sub_graduation_affichable)return;
		if(type_graduation=="grande" && this.trans_index_grand<this.trans_graduations_grandes.length-1)
		{
			this.trans_graduations_grandes[this.trans_index_grand].position.x=x+this.x;
			this.trans_graduations_grandes[this.trans_index_grand].material.alpha=transparence;
			if(this.affichage_valeurs_graduations_decimales && this.letiquette_est_a_representer(etiquette,true) && !this.etiquette_deja_represente(etiquette))
			{
				this.trans_graduations_grandes_etiquettes[this.trans_index_grand].position.x=x+this.x;
				if(hauteur_artificel==0)this.trans_graduations_grandes_etiquettes[this.trans_index_grand].position.y=this.hauteur_grande_graduation/2.0*transparence+this.hauteur_etiquette/2.0*transparence+this.y;
				else this.trans_graduations_grandes_etiquettes[this.trans_index_grand].position.y=hauteur_artificel/2.0+this.hauteur_etiquette*transparence/2.0+this.y;
				this.trans_graduations_grandes_etiquettes[this.trans_index_grand].material.alpha= transparence;
				if(this.valeur_de_graduation_trans[this.trans_index_grand]!=valeur)
				{
					this.remplir_texte(((this.trans_graduations_grandes_etiquettes[this.trans_index_grand].material as StandardMaterial).diffuseTexture as DynamicTexture),etiquette);
					((this.trans_graduations_grandes_etiquettes[this.trans_index_grand].material as StandardMaterial).diffuseTexture as DynamicTexture).update();
				}
				this.trans_graduations_grandes_etiquettes[this.trans_index_grand].scaling.x = transparence;
				this.trans_graduations_grandes_etiquettes[this.trans_index_grand].scaling.y = transparence;
				(this.trans_graduations_grandes_etiquettes[this.trans_index_grand].material as StandardMaterial).alpha=transparence
			}
			else if(this.letiquette_est_a_representer(etiquette,false) && !this.etiquette_deja_represente(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"grande",x,transparence)
			}
			this.trans_graduations_grandes[this.trans_index_grand].scaling.x=transparence<this.largeur_minimale?this.largeur_minimale:transparence;
			this.trans_graduations_grandes[this.trans_index_grand].scaling.y=transparence;
			this.valeur_de_graduation_trans[this.trans_index_grand]=valeur
			this.valeur_trans_graduations_grandes[this.trans_index_grand]=valeur;
			this.trans_index_grand++;
		}
		else if(type_graduation=="moyenne" && this.trans_index_moyen<this.trans_graduations_moyennes.length-1)
		{
			this.trans_graduations_moyennes[this.trans_index_moyen].position.x=x+this.x
			this.trans_graduations_moyennes[this.trans_index_moyen].material.alpha=transparence
			this.trans_graduations_moyennes[this.trans_index_moyen].scaling.x=transparence<this.largeur_minimale?this.largeur_minimale:transparence
			this.trans_graduations_moyennes[this.trans_index_moyen].scaling.y=transparence

			if(this.la_graduation_est_hover(etiquette)){
				(this.trans_graduations_moyennes[this.trans_index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
				this.trans_graduations_moyennes[this.trans_index_moyen].scaling.x=1.2;
			} else if(this.la_graduation_est_select(etiquette)){
				(this.trans_graduations_moyennes[this.trans_index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_select as StandardMaterial).diffuseColor
				this.trans_graduations_moyennes[this.trans_index_moyen].scaling.x=2.0
			}else {
				(this.trans_graduations_moyennes[this.trans_index_moyen].material as StandardMaterial).diffuseColor = (this.couleur_graduation_defaut as StandardMaterial).diffuseColor
				this.trans_graduations_moyennes[this.trans_index_moyen].scaling.x=0.7
			}

			if(this.letiquette_est_a_representer(etiquette,false) && !this.etiquette_deja_represente(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"moyenne",x,transparence)
			}
			this.valeur_de_graduation_trans[this.nb_graduations_maximal/10+2+this.trans_index_moyen]=valeur
			this.valeur_trans_graduations_moyennes[this.trans_index_moyen]=valeur;

			this.trans_index_moyen++;
		}
		else if(this.trans_index_petit<this.trans_graduations_petites.length-1)
		{
			this.trans_graduations_petites[this.trans_index_petit].position.x=x+this.x
			this.trans_graduations_petites[this.trans_index_petit].material.alpha=transparence
			this.trans_graduations_petites[this.trans_index_petit].scaling.x=transparence<this.largeur_minimale?this.largeur_minimale:transparence
			this.trans_graduations_petites[this.trans_index_petit].scaling.y=transparence

			if(this.la_graduation_est_hover(etiquette)){
				(this.trans_graduations_petites[this.trans_index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_hover as StandardMaterial).diffuseColor
				this.trans_graduations_petites[this.trans_index_petit].scaling.x=1.2;
			} else if(this.la_graduation_est_select(etiquette)){
				(this.trans_graduations_petites[this.trans_index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_select as StandardMaterial).diffuseColor
				this.trans_graduations_petites[this.trans_index_petit].scaling.x=2.0
			}else {
				(this.trans_graduations_petites[this.trans_index_petit].material as StandardMaterial).diffuseColor = (this.couleur_graduation_defaut as StandardMaterial).diffuseColor
				this.trans_graduations_petites[this.trans_index_petit].scaling.x=0.5
			}

			if(this.letiquette_est_a_representer(etiquette,false) && !this.etiquette_deja_represente(etiquette))
			{
				this.mettre_etiquette_specifique(etiquette,"petite",x,transparence)
			}
			this.valeur_de_graduation_trans[(this.nb_graduations_maximal/10+2)+(this.nb_graduations_maximal/10+2)+this.trans_index_petit]=valeur
			this.valeur_trans_graduations_petites[this.trans_index_petit]=valeur;

			this.trans_index_petit++
		}
	}

	effacer_toute_les_graduations():void
	{
		var i:number=0
		for(i=0;i<this.graduations_specifiques_etiquettes.length;i++)
		{
			this.graduations_specifiques_etiquettes[i].material.alpha=0.0
			this.graduations_specifiques_etiquettes[i].position.x=1000.0
		}
		for(i=0;i<this.graduations_grandes.length;i++)
		{
			this.graduations_grandes[i].material.alpha=0.0;
			this.graduations_grandes[i].position.x=1000.0
			//this.scene.getMeshById(this.graduations_grandes[i].id+"_hitBox").isPickable =false;
			this.graduations_grandes_etiquettes[i].material.alpha=0.0;
			this.graduations_grandes_etiquettes[i].position.x=1000.0
			
		}
		for(i=0;i<this.graduations_moyennes.length;i++)
		{
			this.graduations_moyennes[i].material.alpha=0.0;
			this.graduations_moyennes[i].position.x=1000.0
			//this.scene.getMeshById(this.graduations_moyennes[i].id+"_hitBox").isPickable =false;
		}
		for(i=0;i<this.graduations_petites.length;i++)
		{
			this.graduations_petites[i].material.alpha=0.0;
			this.graduations_petites[i].position.x=1000.0
			//this.scene.getMeshById(this.graduations_petites[i].id+"_hitBox").isPickable =false;
		}
		this.index_grand=0;
		this.index_moyen=0;
		this.index_petit=0;
		this.index_specifiques_etiquette=0;
	}

	effacer_toute_les_graduations_trans():void
	{
		var i:number=0
		for(i=0;i<this.trans_graduations_grandes.length;i++)
		{
			this.trans_graduations_grandes[i].material.alpha=0.0;
			this.trans_graduations_grandes[i].position.x=1000.0
			this.trans_graduations_grandes_etiquettes[i].material.alpha=0.0;
			this.trans_graduations_grandes_etiquettes[i].position.x=1000.0
			//this.scene.getMeshById(this.trans_graduations_grandes[i].id+"_hitBox").isPickable =false;
		}
		for(i=0;i<this.trans_graduations_moyennes.length;i++)
		{
			this.trans_graduations_moyennes[i].material.alpha=0.0;
			this.trans_graduations_moyennes[i].position.x=1000.0
			//this.scene.getMeshById(this.trans_graduations_moyennes[i].id+"_hitBox").isPickable =false;
		}
		for(i=0;i<this.trans_graduations_petites.length;i++)
		{
			this.trans_graduations_petites[i].material.alpha=0.0;
			this.trans_graduations_petites[i].position.x=1000.0
			//this.scene.getMeshById(this.trans_graduations_petites[i].id+"_hitBox").isPickable =false;
		}
		this.trans_index_grand=0;
		this.trans_index_moyen=0;
		this.trans_index_petit=0;
	}

	plus_proche_resolution(val:number,resolution:number):number
	{
		let rep:number
		rep=Math.round(val/resolution)*resolution
		return(rep)
	}

	afficher_graduations_entre_deux_valeurs_trans(transparence:number):void
	{
		var hg:string=""
		var eq:string = ""
		var i:number=0
		var vx:number=this.position_centre_valeur
		var px:number=this.position_centre_geo
		for(i=1;i<this.nb_graduations_maximal/2*10-1;i++)
		{
			if(i % 100 !=0)
			{
				vx=this.position_centre_valeur+i*(this.resolution_valeur/10)
				px=this.position_centre_geo+i*(this.resolution_geo/10)
				if(i % 10 == 0)
				{
					hg = "grande"
					eq = (Math.round(vx*1000000)/1000000).toString()
				}
				else if(i % 5 == 0)
				{
					hg = "moyenne"
				}
				else hg = "petite"
				if(Math.abs(px)<this.longueur_axe_affichee/2 && !this.valeur_interdite(vx))
				{
					if(i % 50 ==0)
					{
						this.mettre_graduation_trans(hg,px,vx,transparence,vx,this.hauteur_moyenne_graduation)
					}
					else this.mettre_graduation_trans(hg,px,vx,transparence,vx)
				}
				if(i!=0)
				{
					vx=this.position_centre_valeur-i*(this.resolution_valeur/10)
					px=this.position_centre_geo-i*(this.resolution_geo/10)
					if(i % 10 == 0)
					{
						hg = "grande"
						eq = (Math.round(vx*1000000)/1000000).toString()
					}
					else if(i % 5 == 0)
					{
						hg = "moyenne"
					}
					else hg = "petite"
					if(Math.abs(px)<this.longueur_axe_affichee/2 && !this.valeur_interdite(vx))
					{
						if(i % 50 ==0)
						{
							this.mettre_graduation_trans(hg,px,vx,transparence,vx,this.hauteur_moyenne_graduation)
						}
						else this.mettre_graduation_trans(hg,px,vx,transparence,vx)
					}
				}
			}
		}
		this.auto_rameneur()
	}

	estimer_transparence():number
	{
		var rep:number
		rep=(this.resolution_geo-this.resolution_geo_min)/(this.resolution_geo_max-this.resolution_geo_min)
		return(rep)
	}

	valeur_interdite(vx:number):boolean
	{
		return(vx<this.borne_min || vx>this.borne_max);
	}

	afficher_graduations_entre_deux_valeurs(transparence:number):void
	{
		this.valeur_etiquete=[]
		this.effacer_toute_les_graduations()
		this.effacer_toute_les_graduations_trans()
		var hg:string=""
		var eq:string = ""
		var i:number=0
		var vx:number=this.position_centre_valeur
		var px:number=this.position_centre_geo
		for(i=0;i<this.nb_graduations_maximal/2-1;i++)
		{
			vx=this.position_centre_valeur+i*this.resolution_valeur
			px=this.position_centre_geo+i*this.resolution_geo
			if(i % 10 == 0)
			{
				hg = "grande"
				if(transparence==1.0)eq = (Math.round(vx*1000000)/1000000).toString()
			}
			else if(i % 5 == 0)
			{
				hg = "moyenne"
			}
			else hg = "petite"
			if(Math.abs(px)<this.longueur_axe_affichee/2 && !this.valeur_interdite(vx))
			{
				this.affichage_val_max=vx
				this.mettre_graduation(hg,px,vx,transparence,vx)
			}
			if(i!=0)
			{
				vx=this.position_centre_valeur-i*this.resolution_valeur
				px=this.position_centre_geo-i*this.resolution_geo
				if(i % 10 == 0)
				{
					hg = "grande"
					if(transparence==1.0)eq = (Math.round(vx*1000000)/1000000).toString()
				}
				else if(i % 5 == 0)
				{
					hg = "moyenne"
				}
				else hg = "petite"
				if(Math.abs(px)<this.longueur_axe_affichee/2 && !this.valeur_interdite(vx))
				{
					this.affichage_val_min=vx
					this.mettre_graduation(hg,px,vx,transparence,vx)
				}
			}
		}
		this.afficher_graduations_entre_deux_valeurs_trans(this.estimer_transparence())
	}

	preparer_type_graduations(nombres:number):void
	{
		var i:number=0
		for(i=0;i<nombres/10+2;i++)
		{
			this.graduations_grandes.push(this.faire_graduation("grande"+i.toString(),0.0,this.hauteur_grande_graduation,"0.0",1.0,this.largeur_grande_graduations))
			this.graduations_grandes_etiquettes.push( this.scene.getMeshByName("graduation_grande"+i.toString()+"_text") as Mesh)
			this.valeur_de_graduation.push(0.0)
			this.graduations_specifiques_etiquettes.push(this.ecrir_text("etiquette_spe_"+i.toString(),0.0,0.0,-0.1,"0.0"))
		}
		for(i=0;i<nombres/10+2;i++)
		{
			this.graduations_moyennes.push(this.faire_graduation("moyenne"+i.toString(),0.0,this.hauteur_moyenne_graduation,"",1.0,this.largeur_moyenne_graduations))
			this.valeur_de_graduation.push(0.0)
		}
		for(i=0;i<nombres;i++)
		{
			this.graduations_petites.push(this.faire_graduation("petite"+i.toString(),0.0,this.hauteur_petite_graduation,"",1.0,this.largeur_petite_graduations))
			this.valeur_de_graduation.push(0.0)
		}
	}

	preparer_type_graduations_trans(nombres:number):void
	{
		var i:number=0
		for(i=0;i<nombres/10+2;i++)
		{
			this.trans_graduations_grandes.push(this.faire_graduation("trans_grande"+i.toString(),0.0,this.hauteur_grande_graduation,"0.0",1.0,this.largeur_grande_graduations,true))
			this.trans_graduations_grandes_etiquettes.push( this.scene.getMeshByName("graduation_trans_grande"+i.toString()+"_text") as Mesh)
			this.valeur_de_graduation.push(0.0)
		}
		for(i=0;i<nombres/10+2;i++)
		{
			this.trans_graduations_moyennes.push(this.faire_graduation("trans_moyenne"+i.toString(),0.0,this.hauteur_moyenne_graduation,"",1.0,this.largeur_moyenne_graduations,false))
			this.valeur_de_graduation_trans.push(0.0)
		}
		for(i=0;i<nombres;i++)
		{
			this.trans_graduations_petites.push(this.faire_graduation("trans_petite"+i.toString(),0.0,this.hauteur_petite_graduation,"",1.0,this.largeur_petite_graduations,false))
			this.valeur_de_graduation_trans.push(0.0)
		}
	}

	traitement_bt_etiquettes():void
	{
		let i:number
		this.etiquettes_ajoute_bt=[]
		for(i=0;i<this.etiquettes_ajoute.length;i++)
		{
			if(this.etiquettes_ajoute[i].search(">")<0 && this.etiquettes_ajoute[i].search("<")<0 && this.etiquettes_ajoute[i].search(":")<0)
			{
				const o = {}
				o["t"]="v"
				o["v"]=Number(this.etiquettes_ajoute[i])
				this.etiquettes_ajoute_bt.push(o)				
			}
			else if(this.etiquettes_ajoute[i].search(":")>=0 && this.etiquettes_ajoute[i].search(">")<0 && this.etiquettes_ajoute[i].search("<")<0)
			{
				const o = {}
				o["t"]="r"
				o["r"]=Number(this.etiquettes_ajoute[i].replace(":",""))
				this.etiquettes_ajoute_bt.push(o)
			}
			else
			{
				const o = {}
				o["t"]="q"
				let s:string[]=this.etiquettes_ajoute[i].split(/[<>:]/)
				o["m"]=Number(s[0])
				o["r"]=Number(s[2])
				o["M"]=Number(s[3])
				this.etiquettes_ajoute_bt.push(o)
			}
		}
		this.etiquettes_supprime_bt=[]
		for(i=0;i<this.etiquettes_supprime.length;i++)
		{
			if(this.etiquettes_supprime[i].search(">")<0 && this.etiquettes_supprime[i].search("<")<0 && this.etiquettes_supprime[i].search(":")<0)
			{
				const o = {}
				o["t"]="v"
				o["v"]=Number(this.etiquettes_supprime[i])
				this.etiquettes_supprime_bt.push(o)				
			}
			else if(this.etiquettes_supprime[i].search(":")>=0 && this.etiquettes_supprime[i].search(">")<0 && this.etiquettes_supprime[i].search("<")<0)
			{
				const o = {}
				o["t"]="r"
				o["r"]=Number(this.etiquettes_supprime[i].replace(":",""))
				this.etiquettes_supprime_bt.push(o)
			}
			else
			{
				const o = {}
				o["t"]="q"
				let s:string[]=this.etiquettes_supprime[i].split(/[<>:]/)
				o["m"]=Number(s[0])
				o["r"]=Number(s[2])
				o["M"]=Number(s[3])
				this.etiquettes_supprime_bt.push(o)
			}
		}
		console.log("IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII")
		console.log(this.etiquettes_supprime_bt)
	}

	determiner_valeur_a_trouver(txt:string,tab0:string[]):number
	{
		var t:string[]=txt.split(/[<>:!]/)
		let d:number = Number(t[0])
		let r:number = Number(t[2])
		let f:number = Number(t[3])
		let p:number[]=[]
		let i:number
		for(i=0;i<t.length-4;i++)
		{
			p.push(Number(t[i+4]))
		}
		var k:boolean=false
		let ret:number
		for(;!k;)
		{
			ret=d+(f-d)*Math.random()
			ret=ret - (ret % r)
			if(ret > d)
			{
				k=true
				for(i=0;i<p.length;i++)
				{
					if(ret % p[i] == 0)k=false;
				}
			}
			else k=false
		}
		let dc:string[]
		let vac:number
		for(i=0;i<tab0.length;i++)
		{
			dc = tab0[i].split("/")
			if(Math.random()<Number(dc[2]))
			{
				vac = Math.trunc((ret - Math.trunc(ret/(Number(dc[0])*10))*(Number(dc[0])*10))/Number(dc[0]))
				ret = ret - vac*Number(dc[0])
				ret = ret + Number(dc[1])*Number(dc[0])
			}
		}
		return(ret)
	}

	initialisation_configuration_navigation():void
	{
		let d:number;
		let f:number;
		if(typeof this.variables["pos_debut_min"] === 'string')
		{
			d=(this.variables["pos_max"]-this.variables["pos_debut_max"]-this.variables["pos_min"])*Math.random()+this.variables["pos_min"]
			f=d+this.variables["pos_debut_max"]
		}
		else
		{
			d = this.variables["pos_debut_min"]
			f = this.variables["pos_debut_max"]
		}
		let c = (0.5*d+0.5*f)
		this.resolution_valeur=this.variables["reso_debut"]
		this.position_centre_valeur=Math.round(c/(this.resolution_valeur*10))*(this.resolution_valeur*10)
		this.resolution_geo=this.longueur_axe_affichee/((f-d)/this.resolution_valeur+2)
		this.position_centre_geo=-(c-this.position_centre_valeur)*this.resolution_geo
		this.borne_min=this.variables["pos_min"]
		this.borne_max=this.variables["pos_max"]
		this.resolution_mini=this.variables["res_min"]
		this.resolution_maxi=this.variables["res_max"]
		this.etiquettes_ajoute=this.variables["etiquettes_suplementaires"].slice()
		this.etiquettes_supprime=this.variables["etiquettes_en_moins"].slice()
		if(this.variables["type_etiquettes"]=="decimale")this.representation=Representation.Decimale
		else if(this.variables["type_etiquettes"]=="fraction")this.representation=Representation.Fraction
		else if(this.variables["type_etiquettes"]=="litherale")this.representation=Representation.Litherale
		else if(this.variables["type_etiquettes"]=="scientifique")this.representation=Representation.Scientifique
		if(this.variables["type_epreuve"]=="placer")this.type_epreuve=Epreuve.Placer
		else if(this.variables["type_epreuve"]=="nommer")this.type_epreuve=Epreuve.Nommer
		this.ecart_max_tolere=this.variables["ecart_max_tolere"];
		this.tentatives_max=this.variables["nb_tentative_max"];
		this.fuel_translation_max=this.variables["fuel_translation"]
		this.fuel_homotethie_max=this.variables["fuel_zoom"]
		this.limite_temps=this.variables["limite_temps"]
		this.valeur_a_trouver=this.determiner_valeur_a_trouver(this.variables["valeur_a_trouver"],this.variables["ajustement_valeur_a_trouver"])
		this.nb_joker_max=this.variables["nb_joker"]
		this.traitement_bt_etiquettes()
		this.tentatives=this.tentatives_max
		if(this.variables["activation_du_segment"]=="oui")
		{
			this.activation_du_segment=true;
		}
		if(this.variables["desactiver_etiquettes_decimales"]=="oui")
		{
			this.affichage_valeurs_graduations_decimales=false;
		}
		else
		{
			this.affichage_valeurs_graduations_decimales=true;
		}
		if(this.variables["effacer_sub_graduation"]=="oui")
		{
			this.sub_graduation_affichable=false
		}
		this.demarage_nouvelle_manche()
	}

	async le_temps_est_fini()
	{
		await this.envoyer_instruction("Malheureusement, tu n'as plus de temps au chronomètre. Tu as perdu.", true)
		this.perdue()
	}

	async plus_de_carburant()
	{
		await this.envoyer_instruction("Tu n'as plus de carburant, tu a perdu !", true)
		this.perdue()
	}

	reinitialisateur()
	{
		this.scene.meshes.forEach(mesh => 
		{
    		if (mesh.dispose) mesh.dispose();  // supprime mesh et libère mémoire
		});
		this.index_specifiques_etiquette=0
		this.index_grand=0
		this.index_moyen=0
		this.index_petit=0
		this.trans_index_grand=0
		this.trans_index_moyen=0
		this.trans_index_petit=0
		this.valeur_de_graduation=[]
		this.valeur_de_graduation_trans=[]
		this.graduations = []
		this.graduations_petites.forEach(mesh => {mesh.dispose()})
		this.graduations_petites = []
		this.graduations_moyennes.forEach(mesh => {mesh.dispose()})
		this.graduations_moyennes = []
		this.graduations_grandes.forEach(mesh => {mesh.dispose()})
		this.graduations_grandes = []
		this.valeur_graduations_petites = []
		this.valeur_graduations_moyennes = []
		this.valeur_graduations_grandes = []
		this.trans_graduations_petites.forEach(mesh => {mesh.dispose()})
		this.trans_graduations_petites = []
		this.trans_graduations_moyennes.forEach(mesh => {mesh.dispose()})
		this.trans_graduations_moyennes = []
		this.trans_graduations_grandes.forEach(mesh => {mesh.dispose()})
		this.trans_graduations_grandes = []
		this.graduations_grandes_etiquettes.forEach(mesh => {mesh.dispose()})
		this.graduations_grandes_etiquettes = []
		this.graduations_specifiques_etiquettes.forEach(mesh => {mesh.dispose()})
		this.graduations_specifiques_etiquettes = []
		this.valeur_etiquete=[]
		this.trans_graduations_grandes_etiquettes.forEach(mesh => {mesh.dispose()})
		this.trans_graduations_grandes_etiquettes=[]
		this.gui.dispose()
	}

	gagnee():void
	{
		this.waitUserAnswer.next({ success: true, response: this.derniere_valeur_choisi });
		//this.reinitialisateur()
	}

	perdue():void
	{
		this.waitUserAnswer.next({ success: false, response: this.derniere_valeur_choisi });
		//this.reinitialisateur()
	}

	async lancement_du_compte_a_rebourd()
	{
		for(;this.compte_a_rebour>=0;)
		{
			this.compte_a_rebour-=1.0
			this.mettre_a_jour_vignettes()
			await this.wait(1000)
		}
		this.le_temps_est_fini()
	}

	demarage_nouvelle_manche():void
	{
		// recharger joker
		this.instruction.alpha=0; this.bouton_instruction.alpha=0; this.fenetre_instruction.alpha=0; this.bouton_instruction.isVisible = false;
		this.etiquettes_joker=[]
		this.nb_joker=this.nb_joker_max
		if(this.tentatives>0)this.bouton_tentative.image!.source = "assets/gabarits/droite_graduee/CTAfleche-Start.webp";
		if(this.nb_joker>0)this.bouton_joker.image!.source = "assets/gabarits/droite_graduee/JokerA-Start.webp";
		// recharger fuel
		this.fuel_translation=this.fuel_translation_max
		this.fuel_homotethie=this.fuel_homotethie_max
		// replacer le cadre
		let d:number;
		let f:number;
		if(typeof this.variables["pos_debut_min"] === 'string')
		{
			d=(this.variables["pos_max"]-this.variables["pos_debut_max"]-this.variables["pos_min"])*Math.random()+this.variables["pos_min"]
			f=d+this.variables["pos_debut_max"]
		}
		else
		{
			d = this.variables["pos_debut_min"]
			f = this.variables["pos_debut_max"]
		}
		let c = (0.5*d+0.5*f)
		console.log("d : "+d.toString()+"\nf : "+f.toString()+"\nc : "+c.toString())
		this.resolution_valeur=this.variables["reso_debut"]
		this.position_centre_valeur=Math.round(c/(this.resolution_valeur*10))*(this.resolution_valeur*10)
		this.resolution_geo=this.longueur_axe_affichee/((f-d)/this.resolution_valeur+2)
		this.position_centre_geo=-(c-this.position_centre_valeur)*this.resolution_geo
		console.log("res_val : "+this.resolution_valeur.toString()+"\np_c_val : "+this.position_centre_valeur)
		console.log("p_c_geo : "+this.position_centre_geo.toString()+"\nr_geo : "+this.resolution_geo.toString())
		// recharger limite de temps
		if(this.limite_temps!=0.0)
		{
			this.compte_a_rebour=this.limite_temps
			// lancer le compte a rebour
			this.lancement_du_compte_a_rebourd()
		}
		// voir type d epreuve
		if(this.type_epreuve==Epreuve.Placer)
		{
			// choisir le bon outil
			this.les_instructions_a_garder="Tu dois trouver sur la graduation le nombre : "+this.valeur_a_trouver.toString() + "."
			this.envoyer_instruction("")
			this.demande_retirer_outil()
		}
		else if(this.type_epreuve==Epreuve.Nommer)
		{
			this.envoyer_instruction("Dis-moi, à quel nombre cette graduation correspond ? Réponds-moi en dessous.")
			this.demande_retirer_outil()
			//this.centrer_sur_une_valeur(this.valeur_a_trouver)
			this.creer_interface_de_saisie_de_reponse()
			// la colorier en jaune
			this.mettre_graduation_en_selection(this.valeur_a_trouver)
		}
		this.mettre_a_jour_vignettes()
	}

	mettre_a_jour_vignettes():void
	{
		// tentative
		this.vignette_tentative.text = "x"+this.tentatives.toString()
		// translation
		if(this.fuel_translation_max==0)
		{
			this.vignette_translation.text = "Illim"
		}
		else
		{
			this.vignette_translation.text = (Math.trunc((this.fuel_translation/this.fuel_translation_max)*100)).toString()+"%"
		}
		// homothethie
		if(this.fuel_homotethie_max==0)
		{
			this.vignette_homotethie.text = "Illim"
		}
		else
		{
			this.vignette_homotethie.text = (Math.trunc((this.fuel_homotethie/this.fuel_homotethie_max)*100)).toString()+"%"
		}
		// joker
		this.vignette_joker.text = "x"+this.nb_joker.toString()
		if(this.nb_joker === 0){
			this.vignette_joker.alpha = 0;
			this.bouton_joker.alpha = 0;
		}
		// timer
		if(this.limite_temps==0)
		{
			this.vignette_compte_a_rebour.text = "Illim"
		}
		else
		{
			this.vignette_compte_a_rebour.text = this.compte_a_rebour.toString()
		}
		if(this.nb_joker<=0)
		{
			if(this.nb_joker<=0)
			{
				this.bouton_joker.image!.source = "assets/gabarits/droite_graduee/JokerA-Blocked.webp";
			}
		}
	}

	mise_en_place_variables_pour_teste():void
	{
		this.variables["pos_debut_min"] = 0;
		this.variables["pos_debut_max"] = 1000;
		this.variables["reso_debut"] = 10;
		this.variables["pos_min"] = -1;
		this.variables["pos_max"] = 1010;
		this.variables["res_min"] = 10;
		this.variables["res_max"] = 10;
		this.variables["etiquettes_suplementaires"] = [": 100"];
		this.variables["etiquettes_en_moins"] = [];
		this.variables["type_etiquettes"] = "decimale";
		this.variables["type_epreuve"] = "placer"; 
		this.variables["ecart_max_tolere"] = 10.0;
		this.variables["nb_tentative_max"] = 2;
		this.variables["fuel_translation"] = 0.0;
		this.variables["fuel_zoom"] = 0.0;
		this.variables["limite_temps"] = 0;
		this.variables["valeur_a_trouver"] = "0 < n : 1 < 999 ! 1000";
		this.variables["nb_joker"] = 0;
		this.variables["ajustement_valeur_a_trouver"] = ["10 / 0 / 0.5","10 / 9 / 0.5"];
		this.variables["desactiver_etiquettes_decimales"] = "oui";
		this.variables["effacer_sub_graduation"] = "oui";
		this.variables["activation_du_segment"] = "oui"
	}

	mise_en_place_de_l_exercice():void
	{
		//this.mise_en_place_variables_pour_teste()
		console.log("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH")
		console.log(this.variables)
		this.initialisation_configuration_navigation()
	}

	getCurrentOperation():string
	{
		return this.les_instructions_a_garder;
	}

    buildscene() : void
    {	(window as any).ci=this
		if(this.graduations_petites.length==0)
		{
			this.faire_couleurs()
			this.faire_arriere_plan()
			this.faire_axe()
			this.faire_segment()
			this.creer_menu()
			this.preparer_type_graduations(this.nb_graduations_maximal)
			this.preparer_type_graduations_trans(this.nb_graduations_maximal)
			this.scene.onPointerObservable.clear();
			this.addMouseWheelPinchEvent()
		}
		this.mise_en_place_de_l_exercice()
		this.afficher_graduations_entre_deux_valeurs(1.0)
		this.demande_outil_placeur();
    }
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */
    /*************************************************************************************************************** */

	getBackground(): Mesh {
		if (!this.background) {
			window.store.getters.cabri.Scene.meshes.forEach(async m => {
				if (m.id === "background") {
					this.background = m;
				}
			});
		}
		return this.background;
	}

	/**
	 * RESIZE CABRI (from CM) -> Update DOM Cabri elements
	 * @param holoMode Holo mode
	 * @param platform Platform
	 */
	async updateCabriPosition(holoMode: string = null): Promise<void> {
		if (this.page.variable?.activity === justePointActivity.basket) {
			this.dataService.forceBackgroundTexture =
				"/assets/gabarits/jeu_juste_point/background_basket" + (this.globalService.lowPerformanceMode ? "_ios" : "") + ".jpg";
		} else {
			this.dataService.forceBackgroundTexture = null;
		}
		return await super.updateCabriPosition(holoMode, "jeuJustePoint");
	}
	async updateGabaritBackground(renderCanvas) {
		this.scene.meshes.forEach(async (m: Mesh) => {
			if (m.id === "background") {
				this.background = m;

				this.checkFlatHoloMode(m);
				await this.switchBackgroundLauncher(m, renderCanvas.clientHeight, renderCanvas.clientWidth);
				console.log("cabri background resized");
				this.setBackgroundPosition();
			}
		});
	}

	/**
	 * Remediation meshes to be visible
	 */
	keepRemediationElements() {
		if (this.page.variable.activity === justePointActivity.basket) {
			this.assetsContainerBasket.meshes.forEach((currentMesh: TargetMesh) => {
				currentMesh.isVisible = currentMesh.remediation ? true : false;
			});
		}
	}

	/**
	 * Show or not meshes according to remediation/newQuestion/scenario/mascotte anim
	 */
	displayMeshes(show: boolean) {
		if (this.page.variable.activity === justePointActivity.basket) {
			if (this.assetsContainerBasket) {
				this.assetsContainerBasket.meshes.forEach((currentMesh: TargetMesh) => {
					currentMesh.isVisible = show;
				});
			}
		} else {
			if (this.assetsContainerOnTheRoad) {
				this.assetsContainerOnTheRoad.meshes.forEach((currentMesh: TargetMesh) => {
					currentMesh.isVisible = show;
					currentMesh.getChildMeshes(false).forEach(element => {
						element.isVisible = show;
					});
				});
				if (this.advancedTexture) {
					this.advancedTexture.rootContainer.isVisible = show;
				}
			}
		}
	}

	checkActivityChange(): boolean {
		return true;
	}

	saveDom() {
		super.saveDom();
		this.dataService.currentSavedDom = "jeuJustePoint";
	}

	restoreDom() {
		super.restoreDom();
		this.startRender();
	}

	clearResponse(mode: string, value: any): Promise<any> {
		return;
	}

	setResponse(mode: string, value: any) {
		// display response
	}

	onScenereadyInit() {
		this.scene = window.store.getters.cabri.Scene;
		this.engine = window.store.getters.cabri.Engine;
	}

	/**
	 * Get background mesh picked point infos when mouse is over the mesh
	 */
	getGroundPosition(): Vector3 {
		const pickinfo = this.scene.pick(
			this.scene.pointerX,
			this.scene.pointerY,
			this.page.variable.activity === justePointActivity.onTheRoad ? this.isRoadGroundMesh : null,
			true,
			this.page.variable.activity === justePointActivity.onTheRoad ? this.camera : this.cameraHud
		);
		if (pickinfo.hit) {
			return pickinfo.pickedPoint;
		}

		return null;
	}

	isRoadGroundMesh(mesh: AbstractMesh) {
		const elligibleBackgroundMesh = ["leftRoad", "rightRoad", "upperGround", "lowerGround", "road"];
		return elligibleBackgroundMesh.includes(mesh.name);
	}

	pointerDown(mesh: Mesh) {
		this.currentMesh = mesh;
		this.draggablePosition = this.getGroundPosition();
	}

	pointerMove() {
		
	}

	async pointerUp() {
		this.draggablePosition = null;
	}



	/**
	 * Collision between ball and hoop
	 */
	checkResponse(targetMesh: CollisionPosition, souceMesh: CollisionPosition, mesh?) {
		if (
			souceMesh.positionTopY >= targetMesh.positionBottomY &&
			souceMesh.positionBottomY <= targetMesh.positionTopY &&
			souceMesh.positionLeftX >= targetMesh.positionLeftX &&
			souceMesh.positionRightX <= targetMesh.positionRightX
		) {
			return true;
		}
	}

	getBallPosition(ballCenterOrigin: boolean): CollisionPosition {
		const currentMesh = this.getMeshSizeInfos(this.basketBallMesh);
		let positionLeftX: number;
		let positionRightX: number;
		if (ballCenterOrigin) {
			positionRightX = positionLeftX = this.basketBallMesh.position.x;
		} else {
			positionLeftX = this.basketBallMesh.position.x + currentMesh.extendSizeWorld.x;
			positionRightX = this.basketBallMesh.position.x - currentMesh.extendSizeWorld.x;
		}
		return {
			positionLeftX,
			positionRightX,
			positionBottomY: this.basketBallMesh.position.y - currentMesh.extendSizeWorld.y,
			positionTopY: this.basketBallMesh.position.y + currentMesh.extendSizeWorld.y
		};
	}

	checkResponsedMeshValidity(mesh: TargetMesh, forceExactValue: boolean) {
		let success = false;
		let targettedBrokenMesh: TargetMesh;

		if (this.page.variable.chooseExactNumber || forceExactValue) {
			if (forceExactValue) {
				const index = this.bigScaleBars.findIndex(currMesh => {
					return currMesh.value === mesh.value;
				});
				const isLastElement = index === this.bigScaleBars.length - 1;

				targettedBrokenMesh = this.targetMeshBrokenBasket.find(currMesh => {
					return mesh.value === (isLastElement ? currMesh.rangeValue.to : currMesh.rangeValue.inital);
				});
			} else {
				targettedBrokenMesh = this.targetMeshBrokenBasket.find(currMesh => {
					return mesh.value === currMesh.value;
				});
			}
			success = mesh.value === this.page.variable.expectedResult.valueOf() ? true : false;
		} else {
			targettedBrokenMesh = this.targetMeshBrokenBasket.find(currMesh => {
				return mesh.rangeValue.from === currMesh.rangeValue.from;
			});
			if (
				mesh.rangeValue.from <= this.page.variable.expectedResult.valueOf() &&
				this.page.variable.expectedResult.valueOf() <= mesh.rangeValue.to
			) {
				success = true;
			}
		}

		return { success, targettedBrokenMesh };
	}

	enableDragAndDrop() {
		let draggableMesh: Mesh;
		let pickResult: PickingInfo;
		this.pointerObs = this.scene.onPointerObservable.add(pointerInfo => {
			if ((pointerInfo.event as any).preventDefault) {
				(pointerInfo.event as any).preventDefault();
			}

			switch (pointerInfo.type) {
				case PointerEventTypes.POINTERDOWN:
					pickResult = this.scene.pick(
						this.scene.pointerX,
						this.scene.pointerY,
						null,
						false,
						this.page.variable.activity === justePointActivity.onTheRoad ? this.camera : this.cameraHud
					);
					if (pickResult.hit) {
						draggableMesh = this.getLastParentMesh(pickResult.pickedMesh as Mesh);
						if ((draggableMesh as TargetMesh)?.draggable) {
							this.pointerDown(draggableMesh);
						}
					}
					break;
				case PointerEventTypes.POINTERUP:
					this.pointerUp();
					break;
				case PointerEventTypes.POINTERMOVE:
					this.pointerMove();
					break;
			}
		});
	}


	/**
	 * Basket - Confetti coming out from broken basket good answer
	 */
	async generateConfetti(targettedHoopPosition: Vector3) {
		const particlesRightAnswer = new BabylonJsConfetti(this, 1000, 1500, ParticleAnimName.basket, targettedHoopPosition);
		await particlesRightAnswer.runParticles();
	}

	getMeshSizeInfos(mesh): BoundingBox {
		return mesh.getBoundingInfo().boundingBox;
	}


	async launchAgainActivity() {
		// await this.removeScene();
		await this.launchActivity();
	}

	/**
	 * Convert svg generaterd by mathJax into an image in order to display in the box
	 */
	mathJaxSvgToImg(currIndex: number) {
		return new Promise(resolveFinal => {
			let denominateur: number;
			if (this.page.variable.unitStep instanceof Fraction) {
				denominateur = this.page.variable.unitStep.denominateur;
			} else if (this.page.variable.nbMin instanceof Fraction) {
				denominateur = this.page.variable.nbMin.denominateur;
			} else {
				denominateur = this.page.variable.unitStep.valueOf();
			}
			MathJax.tex2svgPromise(`\\frac{${this.page.variable.nbMin.valueOf() + currIndex}}{${denominateur}}`).then(element => {
				this.page.mathJaxDiv.nativeElement.appendChild(element);
				MathJax.startup.document.clear();

				const allMySvgs = this.page.mathJaxDiv.nativeElement.querySelectorAll("svg");
				const svgsLength = allMySvgs.length - 1;
				allMySvgs[svgsLength].appendChild(MathJax.defsGlobalCaching);
				const url = "data:image/svg+xml;base64," + window.btoa(allMySvgs[svgsLength].outerHTML);
				const img = new Image();
				return new Promise(() => {
					img.onload = () => {
						resolveFinal(img);
					};
					img.onerror = err => {
						console.log("errerr", err);
					};
					img.src = url;
				});
			});
		});
	}


	/**
	 * If displayed number is a whole number so display as number and not as Fraction
	 */
	isWholeNumber(currIndex: number): boolean {
		return this.bigScaleBars[currIndex].value.valueOf() - Math.floor(this.bigScaleBars[currIndex].value.valueOf()) === 0;
	}

	/**
	 * Basket - Check if nbMin and nbMax is not in the fraction type
	 */
	nbMinMaxisNotFraction(currIndex: number): boolean {
		return (
			(this.bigScaleBars[currIndex] &&
				this.bigScaleBars[currIndex].value === this.page.variable.nbMin.valueOf() &&
				!(this.page.variable.nbMin instanceof Fraction)) ||
			(this.bigScaleBars[currIndex].value === this.page.variable.nbMax.valueOf() && !(this.page.variable.nbMax instanceof Fraction))
		);
	}

	/**
	 * Precision determine not apply when the result is 0
	 */
	displayedNumberPrecision(value) {
		if (value.toString().includes(".")) {
			return this.basketUnitStepPrecision;
		} else {
			return 0;
		}
	}

	get expectedResultByAccuracy() {
		return this.page.variable.chooseExactNumber
			? this.page.variable.expectedResult.valueOf()
			: Math.floor(this.page.variable.expectedResult.valueOf() as any);
	}

	/**
	 * Get number elements in the graduated scale
	 */
	get numberItems(): number {
		// step for integer is one
		let nbElement;
		if (this.page.variable.unitStep instanceof Fraction) {
			nbElement =
				(this.page.variable.nbMax.valueOf() - this.page.variable.nbMin.valueOf()) * this.page.variable.unitStep.denominateur + 1;
		} else {
			nbElement = (this.page.variable.nbMax.valueOf() - this.page.variable.nbMin.valueOf()) / this.page.variable.unitStep + 1;
		}
		return nbElement;
	}


	createHighLighter() {
		if (!this.hl) {
			this.hl = new HighlightLayer("hl1", this.scene);
			this.alpha = 0;
			this.hl.renderingGroupId = 0;
			this.scene.registerBeforeRender(() => {
				this.alpha += 0.1;

				this.hl.blurHorizontalSize = 0.3 + Math.cos(this.alpha) * 0.6 + 0.6;
				this.hl.blurVerticalSize = 0.3 + Math.sin(this.alpha / 3) * 0.6 + 0.6;
			});
		}
	}


	setBackgroundPosition() {
		if (this.page.variable.activity === justePointActivity.onTheRoad) {
			this.background.position = new Vector3(0, -12, 40);
			this.background.scaling = new Vector3(2.2, 2.2, 2.2);
		} else {
			this.background.position = new Vector3(0, 0, 0);
			this.background.scaling = new Vector3(1.1, 1, 1.1);
		}
	}

	/**
	 * CheckCollision to detec the result of the exercise call on dpointer up event after drag
	 */
	checkRoadCollision() {
		const allOnRoadGround =
			this.targetMesh.length > 0 &&
			this.targetMesh.every(carMesh => {
				return carMesh.intersectsMesh(this.meshs.get("road"), false, true);
			});
		this.buttonValider.isVisible = allOnRoadGround;
	}

	createEnvElement() {
		const tree = this.meshs.get("Tree1") as Mesh;
		this.freezeMaterialOnMesh(tree);
		tree.layerMask = this.camera.layerMask;
		this.assetsContainerOnTheRoad.meshes.push(tree);
		tree.scaling = new Vector3(0.1, 0.1, 0.1);
		tree.position = new Vector3(6, 1.4, 11);
		const tree2 = tree.clone("tree2");
		tree2.scaling = new Vector3(0.1, 0.1, 0.1);
		tree2.position = new Vector3(8, 1.4, 10);
		tree2.rotation.y = (80 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(tree2);
		const tree3 = tree.clone("tree3");
		tree3.scaling = new Vector3(0.1, 0.1, 0.1);
		tree3.position = new Vector3(10, 1.4, 8);
		tree3.rotation.y = (180 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(tree3);
		const tree4 = tree.clone("tree4");
		tree4.scaling = new Vector3(0.1, 0.1, 0.1);
		tree4.position = new Vector3(11, 1.4, 7);
		tree4.rotation.y = (300 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(tree4);
		// pine
		const pine = this.meshs.get("Tree2") as Mesh;
		this.freezeMaterialOnMesh(pine);
		pine.layerMask = this.camera.layerMask;
		this.assetsContainerOnTheRoad.meshes.push(pine);
		pine.scaling = new Vector3(0.1, 0.1, 0.1);
		pine.position = new Vector3(3, 1.4, 11);
		const pine2 = pine.clone("Pine2");
		pine2.scaling = new Vector3(0.16, 0.16, 0.16);
		pine2.position = new Vector3(9, 1.4, 10);
		pine2.rotation.y = (80 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(pine2);
		const pine3 = pine.clone("Pine3");
		pine3.scaling = new Vector3(0.1, 0.1, 0.1);
		pine3.position = new Vector3(-10, 1.4, 2.5);
		pine3.rotation.y = (180 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(pine3);
		const pine4 = pine.clone("Pine4");
		pine4.scaling = new Vector3(0.17, 0.17, 0.17);
		pine4.position = new Vector3(-11.5, 1.4, 9);
		pine4.rotation.y = (300 * Math.PI) / 180;
		this.assetsContainerOnTheRoad.meshes.push(pine4);
		const house = this.meshs.get("Cubo.001") as Mesh;
		this.freezeMaterialOnMesh(house);
		house.getChildMeshes().forEach(element => {
			element.layerMask = this.camera.layerMask;
		});

		house.layerMask = this.camera.layerMask;
		this.assetsContainerOnTheRoad.meshes.push(house);
		house.scaling = new Vector3(0.1, 0.1, 0.1);
		house.position = new Vector3(4.5, 0.56, 8);
		house.rotation = new Vector3(0, (118.8 * Math.PI) / 180, 0);
	}

	/**
	 * freezeMaterial material into a mesh and it's children
	 * @param mesh
	 */
	freezeMaterialOnMesh(mesh: Mesh) {
		mesh.material.freeze();
		if (mesh.getChildMeshes && mesh.getChildMeshes.length > 0) {
			mesh.getChildMeshes().forEach(mesh => {
				this.freezeMaterialOnMesh(mesh as Mesh);
			});
		}
	}


	sendButtonValidate(eventData?: Vector2WithInfo, eventState?: EventState) {
		this.buttonValider.isVisible = false;
		let carTrue = 0;
		const error = [];
		let success = false;
		let reversed = false;
		this.targetMesh.forEach(car => {
			const groundTile = this.targetSubMesh.find(s => s.value === car.value);
			if (groundTile) {
				if (car.intersectsMesh(groundTile as unknown as AbstractMesh, false, false)) {
					carTrue += 1;
				} else {
					if (Array.isArray(this.page.variable.expectedResult)) {
						this.page.variable.expectedResult.forEach(result => {
							const altGroundTile = this.targetSubMesh.find(s => s.value === result.valueOf());
							if (car.intersectsMesh(altGroundTile as unknown as AbstractMesh, false, false)) {
								reversed = true;
							}
						});
					}
					error.push({ color: car.color, correctValue: car.value });
				}
			} else {
				throw new Error("Probleme de 'variable exercice' le nombre rechercher n'existe pas dans les bornes");
			}
		});

		success = carTrue === this.targetMesh.length;
		this.waitUserAnswer.next({ success, response: new ResultOnTheRoad(error), reversed: reversed });
		console.log("success", success);
		console.log("error", error);
	}
	getStepPrecision(currentUnitStep?: number) {
		let unitStep;
		if (!currentUnitStep) {
			unitStep = this.page.variable.unitStep.valueOf();
		} else {
			unitStep = currentUnitStep;
		}
		if (unitStep.toString().includes(".")) {
			const untilCommaInd = unitStep.toString().indexOf(".");
			return unitStep.toString().length - 1 - untilCommaInd;
		} else {
			return 0;
		}
	}

	/**
	 * @returns Return an array of string with the consigne for the exercice
	 * @param secondShot to know if it is the second try and adapt scenario accordingly
	 */
	getConsigneExerciceBasketTTS(secondShot?: boolean): string[] {
		const consigneArrayTTS = [];
		const theFraction = $localize`:consigne jeu juste point type Fraction:la fraction `;
		const toFraction = $localize`:consigne jeu juste point type Fraction:à la fraction `;
		const ofFraction = $localize`:consigne jeu juste point type Fraction:de la fraction `;
		const theNumber = $localize`:consigne jeu juste point type Nombre:le nombre `;
		const toNombre = $localize`:consigne jeu juste point type Nombre:au nombre `;
		const ofNumber = $localize`:consigne jeu juste point type Nombre:du nombre `;
		const toTypeResult = this.page.variable.expectedResult instanceof Fraction ? toFraction : toNombre;
		const theTypeResult = this.page.variable.expectedResult instanceof Fraction ? theFraction : theNumber;
		const ofTypeResult = this.page.variable.expectedResult instanceof Fraction ? ofFraction : ofNumber;

		let phrase = $localize`Mets le ballon dans le panier correspondant ${toTypeResult}`;
		if (!secondShot && this.dataService.teamTotalAwards > 1 && this.dataService.teamTotalAwards < 5) {
			// after the first answer:
			if (!this.consigneScenariosArray || this.consigneScenariosArray.length === 0) {
				if (this.page.accountService.team.length === 1) {
					this.consigneScenariosArray = [
						$localize`Peux-tu atteindre ${theTypeResult}`,
						$localize`Essaye de viser ${theTypeResult}`,
						$localize`Maintenant vise ${theTypeResult}`,
						$localize`Et maintenant ${theTypeResult}`,
						$localize`Lance le ballon dans le panier ${ofTypeResult}`
					]
				} else {
					this.consigneScenariosArray = [
						$localize`Peux-tu atteindre ${theTypeResult}`,
						$localize`Essaye de viser ${theTypeResult}`,
						$localize`Vise ${theTypeResult}`,
						$localize`Peux-tu atteindre ${theTypeResult}`,
						$localize`Lance le ballon dans le panier ${ofTypeResult}`
					]
				}
				AppUtils.shuffleArray(this.consigneScenariosArray);
			}
			const [first, ...rest] = this.consigneScenariosArray;
			this.consigneScenariosArray = rest;
			phrase = first;
		} else if (!secondShot && this.dataService.teamTotalAwards >= 6) {
			// after 6 answers:
			const consigneScenariosFastArray = [
				$localize`Vise ${theTypeResult}`,
				$localize`Dans ${theTypeResult}`,
				this.page.variable.expectedResult instanceof Fraction ? theTypeResult : $localize`Le`,
				this.page.variable.expectedResult instanceof Fraction ? $localize`Maintenant la` : $localize`Maintenant le`,
			]
			const index = Math.floor(Math.random() * consigneScenariosFastArray.length);
			phrase = consigneScenariosFastArray[index];
		} else if (secondShot) {
			// after remediation:
			const consigneScenariosFastArray = [
				$localize`Alors, dans quel panier est ${theTypeResult}`,
				$localize`Mais alors, où se cache donc ${theTypeResult}`,
				$localize`Où est donc ${theTypeResult}`,
				$localize`Mais alors, où se cache ${theTypeResult}`,
				$localize`Donc… Où est ${theTypeResult}`,
				$localize`Du coup, où se trouve ${theTypeResult}`
			]
			const index = Math.floor(Math.random() * consigneScenariosFastArray.length);
			phrase = consigneScenariosFastArray[index];
		}

		this.page.basketCommonPhrase = phrase;
		let expectedResult = "";
		if (this.page.variable.expectedResult instanceof Fraction) {
			expectedResult = this.page.scenario.ttsFraction(this.page.variable.expectedResult);
		} else {
			expectedResult = this.page.variable.expectedResult.valueOf().toString();
		}
		consigneArrayTTS.push(this.page.basketCommonPhrase + expectedResult);
		return consigneArrayTTS;
	}

	/**
	 * @returns Return an array of string with the consigne for the Road exercice
	 */
	getConsigneExerciceRoad(): [string[], string] {
		let opSign: string;
		const stepPrecision = this.getStepPrecision();
		const nb1 = Number(this.page.variable.expectedResult[0].toFixed(stepPrecision));
		const nb2 = Number(this.page.variable.expectedResult[1].toFixed(stepPrecision));
		let pas: number;
		this.page.scenario.resultPhrase = undefined;
		if (this.page.variable.operation !== operation.PlacementDePoint) {
			switch (this.page.variable.operation) {
				case operation.addition:
					opSign = "+";
				break;
				case operation.soustraction:
					opSign = "-";
				break;
			}
			pas = nb2 - nb1;
			const result = eval(nb1 + opSign + pas).toFixed(stepPrecision);
			this.page.scenario.resultPhrase = $localize`Oui`+`, ${nb1} ${opSign} ${pas} =${result} !`;
			this.page.scenario.resultPhraseRemediation = `${nb1} ${opSign} ${pas} =${result} !`;
			// console.error("XXX nb1 = ", nb1);
			// console.error("XXX nb2 = ", nb2);
			// console.error("XXX result phrase = ", this.page.scenario.resultPhrase);
		}

		const consigneArrayDisplayed = [];
		let consigneArrayTTS: string[] = [];
		let consigneTTSRoad;
		const nbrItem = this.targetMesh.length;
		const lesVoitures = $localize`les voitures`;
		const laVoiture = $localize`la voiture`;
		const laLesVoiture = nbrItem > 1 ? lesVoitures : laVoiture;
		consigneArrayDisplayed.push($localize`Place ${laLesVoiture} selon les consignes suivantes : `);
		this.targetMesh.forEach((voiture, index, array) => {

			if (index === 0 || this.page.variable.operation === operation.PlacementDePoint) {
				const kmValue = voiture.value.toString();
				// TEXT:
				consigneArrayDisplayed.push($localize`La voiture ${voiture.color} a roulé ${kmValue} ${DistanceUnit.Km}`);
				// TTS:
				consigneArrayTTS.push($localize`La voiture ${voiture.color} a roulé ${kmValue} ${DistanceUnit.Km}`)
			} else {
				const currentColor = array[index - 1].color;
				if (this.page.variable.operation === operation.addition) {
					const currentKmValue = (voiture.value.valueOf() - array[index - 1].value.valueOf()).toFixed(stepPrecision);
					// TEXT:
					consigneArrayDisplayed.push(
						$localize`La voiture ${voiture.color} est à ${currentKmValue} ${DistanceUnit.Km} devant la voiture ${currentColor}`
					);
					// TTS:
					consigneArrayTTS.push($localize`La ${voiture.color} est à ${currentKmValue} ${DistanceUnit.Km} devant`);
				} else {
					const currentKmValue = (array[index - 1].value.valueOf() - voiture.value.valueOf()).toFixed(stepPrecision);
					// TEXT:
					consigneArrayDisplayed.push(
						$localize`La ${voiture.color} est à ${currentKmValue} ${DistanceUnit.Km} derrière la voiture ${currentColor}`
					);
					// TTS:
					consigneArrayTTS.push($localize`La ${voiture.color} est à ${currentKmValue} ${DistanceUnit.Km} derrière ${currentColor}`);
				}
			}
		});
		if (this.page.currentUser.awardsCurrent.total < 1) {
			// read full consigne the first time
			consigneArrayTTS = consigneArrayDisplayed;
		}
		const virgule = $localize`virgule`;
		const kilometre = $localize`kilomètre`;
		consigneTTSRoad = consigneArrayTTS.reduce((p, n) => p + "! " + n)
		.replace(/\./g, " "+ virgule +" ")
		.replace(/km/g, kilometre);
		console.error("consigneTTSRoad ", consigneTTSRoad);
		return [consigneArrayDisplayed, consigneTTSRoad];
	}

	highlightMesh(active: boolean, mesh: Mesh, wSubMesh = false, color?: Color3) {
		if (wSubMesh && mesh.getChildMeshes()?.length > 0) {
			mesh.getChildMeshes().forEach(subMesh => {
				if (active) {
					this.hl.addMesh(subMesh as Mesh, color ? color : (new Color3(0.01, 0.81, 0.01) as Color3), false);
				} else {
					this.hl.removeMesh(subMesh as Mesh);
				}
			});
		}
		if (active) {
			this.hl.addMesh(mesh, color ? color : (new Color3(0.01, 0.81, 0.01) as Color3), false);
		} else {
			this.hl.removeMesh(mesh);
		}
	}

	highlightCar(active: boolean, color: string | string[] | ResultOnTheRoad) {
		if (Array.isArray(color)) {
			color.forEach(c => {
				const color = this.color.find(co => co.name === c);
				const carMesh = this.targetMesh.find(m => m.color === c);
				this.highlightMesh(
					active,
					carMesh.getChildMeshes(false, cMesh => {
						return cMesh.id.includes("body.body");
					})[0] as Mesh,
					false,
					color.color
				);
			});
		} else if (color instanceof ResultOnTheRoad) {
			color.carsError.forEach(c => {
				const color = this.color.find(co => co.name === c.color);
				const carMesh = this.targetMesh.find(m => m.color === c.color);
				this.highlightMesh(
					active,
					carMesh.getChildMeshes(false, cMesh => {
						return cMesh.id.includes("body.body");
					})[0] as Mesh,
					false,
					color.color
				);
			});
		} else {
			const color3 = this.color.find(co => co.name === color);
			const carMesh = this.targetMesh.find(m => m.color === color);
			this.highlightMesh(
				active,
				carMesh.getChildMeshes(false, cMesh => {
					return cMesh.id.includes("body.body");
				})[0] as Mesh,
				false,
				color3.color
			);
		}
	}


	customLoadingScreen() {
		DefaultLoadingScreen.prototype.displayLoadingUI = () => {
			this.page.customLoader = true;
		};

		DefaultLoadingScreen.prototype.hideLoadingUI = () => {
			this.page.customLoader = false;
		};
	}

	disposeRemediationRoad() {
		this.remediationPlanes.forEach(plane => {
			plane.material?.dispose();
			plane.dispose();
		});
	}
}

results matching ""

    No results matching ""