La rotation des objets – 4

Bienvenue dans ce quatrième article consacré aux axes virtuels basés sur les rotations. Dans le troisième article, nous avons continué notre apprentissage pour la rotation Z et notamment comment translater un point de rotation sur le côté droit au milieu et en arrière. Je vous propose aujourd'hui de découvrir uniquement la correction nécessaire de certains calculs selon la rotation demandée ou le changement d'échelle des modèles dans EEP.

Introduction

Comme d'habitude concernant les fonctions EEP, vous pouvez toujours vous référez à la documentation présente sur le site concernant l'utilisation des différentes fonctions Lua pour EEP. Vous pouvez également consulter cette page afin d'apporter des réponses à vos questions et les explications nécessaires aux fonctions et mots-clés propres au langage Lua.

Si vous voulez écrire vous-même votre script, je vous conseille d'utiliser l'éditeur notepad++ pour profiter de toutes les fonctions d'édition. Cet éditeur est également disponible en français. Ensuite au gré des modifications, un simple copié-collé dans la fenêtre Lua sera parfait.

Cet article sera plus récréatif et moins dense que les précédents avant d'aborder les articles suivants un peu plus avancés. Mais pour le moment, concentrons nous sur la correction des calculs.

Les différents emplacements d'origine des modèles

Avant de rentrer dans le vif du sujet et pour une parfaite compréhension, il est important de démontrer clairement et sans ambiguïté les différents emplacements d'origine des modèles. Pour rappel, le placement d'un point de rotation est le résultat de la méthode utilisée lors de la construction dans les logiciels de modélisation 3D. Les deux principaux axes concernés sont X et Y. Ces affirmations sont basées sur des années de pratique avec EEP et jusqu'à preuve du contraire, je n'ai pas vu d'autres emplacements différents à ce jour. Je vais tous les détailler ci-dessous.

Les différents emplacements sur l'axe X

Sur l'axe X, trois emplacements sont envisageables pour la rotation de base comme nous le montre ce petit dessin :

Emplacement points de rotation axe X dans EEP

Comme nous pouvons le constater, les trois points de rotations de base sont situés à gauche, au centre et à droite. J'ai pu constater 1 ou 2 modèles sur plusieurs centaines !... où la rotation de base était située "quelque part" sur l'axe X. Comme ces modèles sont très rares, j'ai écarté ce cas de figure dans les calculs du script.

Ainsi pour conclure au sujet de l'axe X, retenons ces trois points de rotations d'origine :

  1. A gauche,
  2. Au centre,
  3. A droite
L'emplacement sur l'axe Y

Sur l'axe Y, un seul emplacement est envisageable pour la rotation de base comme nous le montre ce petit dessin :

Emplacement points de rotation axe Y dans EEP

Ici, le seul point de rotation de base est situé au milieu de l'axe Y. Comme l'axe X, j'ai pu constater 1 ou 2 modèles sur quelques centaines !... où la rotation de base était située "quelque part" sur l'axe Y. Comme ces modèles sont très rares, j'ai écarté ce cas de figure dans les calculs du script.

Mais attention, qui dit au milieu de l'axe Y veut dire aussi soit à gauche, au centre ou à droite de l'axe X.

Ainsi pour conclure au sujet de l'axe Y, retenons le seul point de rotation d'origine :

  1. Toujours au milieu sur l'axe Y aussi bien à gauche, au centre ou à droite par rapport à l'axe X.
Les différents emplacements sur l'axe Z

Concernant l'axe Z, dans notre cas on ne peut pas parler directement de point de rotation de base. En effet, lorsqu'on manipule la rotation Z, il faut corriger les positions X et Y car la position Z ne bouge pas.

Lorsque nous aborderons la rotation Y plus simple à manipuler par rapport à la rotation Z, alors oui effectivement à ce moment là, la position Z devra être à son tour corrigée. Mais là encore, il s'agira uniquement de la position Z et non pas de la rotation Z.

Pour conclure sur ce chapitre, j'insiste sans doute un peu trop sur ce sujet, mais la confusion n'est jamais loin pour les utilisateurs débutants ou ceux qui ont du mal à se représenter mentalement les objets dans un environnement 3D. Ce n'est aucunement une critique de ma part mais au contraire, ce chapitre est là pour les aider du mieux possible.

Pourquoi apporter des corrections aux calculs ?

Bonne question !... parce que nous en avons besoin !... Bonne réponse ? 🙂

Pour le comprendre, nous allons nous pencher sur la déclaration des tables suivantes. Elles sont au nombre de trois :

Projet_principal.lua
-- Tables pour corriger les positions (si modification des échelles) selon l'orientation des modèles dans le plan
gTb_Corr_Pos_X = {}
gTb_Corr_Pos_Y = {}
gTb_Corr_Pos_Z = {}

Ces trois tables sont étroitement liées avec celles-ci :

Projet_principal.lua
-- Table pour récupérer la longueur en mètres sur l'axe X des modèles si modification d'échelle
gTb_Ech_Dimension_X = {}
-- Table pour récupérer la largeur en mètres sur l'axe Y des modèles si modification d'échelle
gTb_Ech_Dimension_Y = {}
-- Table pour récupérer la hauteur en mètres sur l'axe Z des modèles si modification d'échelle
gTb_Ech_Dimension_Z = {}

-- Table pour stocker La longueur X des modèles à l'échelle 1
gTb_Long_X_Ech1 = {}
-- Table pour stocker La largeur Y des modèles à l'échelle 1
gTb_Larg_Y_Ech1 = {}
-- Table pour stocker La hauteur Z des modèles à l'échelle 1
gTb_Haut_Z_Ech1 = {}

Pour comprendre la logique liée entre toutes ces tables, je vais commencer par détailler les trois dernières aux lignes n° 36, 38 et 40.

Le point commun entre toutes ces tables est d'enregistrer les dimensions des modèles à l'échelle 1. Ces informations cruciales sont situées dans toutes les fonctions des paramètres communs des modèles. En effet, ces fonctions regroupent les informations propres à un modèle précis et pas à un autre ou celui du voisin !

Exemple avec un modèle au hasard comme le mur en briques... Eh oui pourquoi pas ! après tout nous sommes là pour apprendre et ce qui est rendu possible avec un mur en brique l'est tout autant avec n'importe quel modèle immobilier ou de marchandise ! Nous aurons l'occasion de découvrir d'autres modèles dans les prochains articles.

ID_Modeles.lua
-- ======================================================================
-- =                                                                    =
-- =   Modèle : Mur de voie_5 (mur en briques) du constructeur TL1      =	
-- =   M.ImmoBriqueTL1 concerne les modèles avec les ID :               =
-- =   2, 4, 5, 15, 40, 41, 42, 43, 53, 58, 77, 80, 104, 105, 106       =
-- =                                                                    =
-- ======================================================================

-- Paramètres communs pour le mur en briques
function M.ImmoBriqueTL1(Ar_ID_Lua)

	-- La longueur du mur Ar_ID_Lua à l'échelle 1 est = à 40 mètres
	gTb_Long_X_Ech1[Ar_ID_Lua] = 40
	-- La largeur du mur Ar_ID_Lua à l'échelle 1 est = à 4 mètres
	gTb_Larg_Y_Ech1[Ar_ID_Lua] = 4
	-- La hauteur du mur Ar_ID_Lua à l'échelle 1 est = à 5 mètres
	gTb_Haut_Z_Ech1[Ar_ID_Lua] = 5
	--[[ Variable pour stocker la valeur calculée des rotations
		  à chaque itération de la boucle while ]]
	gTb_Rot_Calcul[Ar_ID_Lua] = 0

	gTb_Rot_Origine[Ar_ID_Lua] = C.ROTATION_ORIGINE_CENTRE
	
end

Les trois tables qui nous intéresse ici sont mises en évidence avec les lignes en surbrillance. Nous avons :

  1. gTb_Long_X_Ech1 : cette table concerne la dimension à l'échelle 1 du modèle sur l'axe X, c'est à dire sa longueur,
  2. gTb_Long_Y_Ech1 : cette table concerne la dimension à l'échelle 1 du modèle sur l'axe Y, c'est à dire sa largeur,
  3. gTb_Long_Z_Ech1 : cette table concerne la dimension à l'échelle 1 du modèle sur l'axe Z, c'est à dire sa hauteur.

Je vous expliquerai comment obtenir ces valeurs à la fin de l'article mais pour le moment restons concentrés sur les tables. Ici dans notre exemple, la longueur de notre modèle est de 40 mètres, sa largeur de 4 mètres et sa hauteur de 5 mètres. Ces valeurs se rapportent au facteur d'échelle égal à 1 comme nous pouvons le constater dans la fenêtre des propriétés par défaut du modèle en question :

Fenêtre des propriétés du mur en brique avec EEP et Lua pour les rotations
Echelles par défaut

Affichons maintenant notre modèle dans la fenêtre 3D :

Mur en briques dans EEP avec Lua en 3D à l'échelle 1
Modèle par défaut à l'échelle 1

Et en vidéo, la rotation Z appliquée sur le côté gauche au milieu :

Gif pour la rotation Z sous EEP à l'échelle 1
Rotation Z sur le côté gauche au milieu à l'échelle 1

Jusqu'ici rien d'anormal, nous retrouvons notre rotation Z comme dans les articles précédents.

Maintenant, amusons-nous à modifier la valeur des échelles comme suit :

  1. Echelle X : valeur 2
  2. Echelle Y : valeur 3
Fenêtre des propriétés du mur en brique avec EEP et Lua à l'échelle 2 pour les rotations
Echelles modifiées

et le résultat dans la fenêtre 3D :

Mur en briques dans EEP avec Lua en 3D à l'échelle 2
Echelles modifiées

Suite à notre modification d'échelle, la longueur X égale à 40 m à l'échelle 1 est passée à 80 m à l'échelle 2 (2 x 40) et la largeur Y égale à 4 m à l'échelle 1 est passée à 12 m à l'échelle 3 (3 x 4).

Regardons le résultat en vidéo :

Gif pour la rotation Z sous EEP à l'échelle 2
Point de rotation non corrigée avec changement d'échelle

Le résultat est tout bonnement ridicule (à moins que ce soit l'effet recherché). A l'échelle 1, la rotation au milieu du bord gauche était parfaitement alignée alors qu'ici la rotation n'est plus du tout alignée sur le bord gauche. Et le problème se reproduira quelque soit les axes de rotations demandés et le point de rotation souhaité ! Bref, rien ne va plus ! ce qui n'est pas acceptable.

Voici le résultat que j'aimerai obtenir pour retrouver mon point de rotation aligné sur le bord gauche au milieu malgré le changement des valeurs d'échelles :

Gif pour la rotation Z sous EEP à l'échelle 2 corrigée
Point de rotation corrigé avec changement d'échelle

Alors quelle est la solution ?

Solution pour les changements d'échelles

Avant tout, je vais afficher les six tables utilisées pour solutionner le problème :

Projet_principal.lua
-- Table pour récupérer la nouvelle longueur en mètres sur l'axe X des modèles si modification d'échelle
gTb_Ech_Dimension_X = {}
-- Table pour récupérer la nouvelle largeur en mètres sur l'axe Y des modèles si modification d'échelle
gTb_Ech_Dimension_Y = {}
-- Table pour récupérer la nouvelle hauteur en mètres sur l'axe Z des modèles si modification d'échelle
gTb_Ech_Dimension_Z = {}
Projet_principal.lua
-- Tables pour corriger les positions (si modification des échelles) selon l'orientation des modèles dans le plan
gTb_Corr_Pos_X = {}
gTb_Corr_Pos_Y = {}
gTb_Corr_Pos_Z = {}

Le début de la solution pour résoudre notre problème commence à la ligne n° 1299 :

Projet_principal.lua
	-- Récupère la longueur en mètres sur l'axe X du modèle après application éventuelle de la nouvelle échelle
	gTb_Ech_Dimension_X[Ar_ID_Lua] = fn_EEPStructureGetScale( Ar_ID_Lua, C.ROTATION_AXE_X, gTb_Long_X_Ech1[Ar_ID_Lua] )

	-- Récupère la largeur en mètres sur l'axe Y du modèle après application éventuelle de la nouvelle échelle
	gTb_Ech_Dimension_Y[Ar_ID_Lua] = fn_EEPStructureGetScale( Ar_ID_Lua, C.ROTATION_AXE_Y, gTb_Larg_Y_Ech1[Ar_ID_Lua] )

	-- Récupère la hauteur en mètres sur l'axe Z du modèle après application éventuelle de la nouvelle échelle
	gTb_Ech_Dimension_Z[Ar_ID_Lua] = fn_EEPStructureGetScale( Ar_ID_Lua, C.ROTATION_AXE_Z, gTb_Haut_Z_Ech1[Ar_ID_Lua] )

Ici nous avons trois tables afin de récupérer les résultats des trois fonctions fn_EEPStructureGetScale(). Malheureusement jusqu'à EEP17 plugin 3, il n'existe pas de fonction Lua pour récupérer la valeur d'un facteur d'échelle comme la position avec EEPStructureGetPosition() ou la rotation au moyen de EEPStructureGetRotation().

Alors on laisse tomber ? certainement pas ! si la fonction n'existe pas et bien nous allons la créer en respectant la même syntaxe des fonctions Lua pour EEP ! Son nom sera EEPStructureGetScale préfixé de fn_ (abrégé de fonction).

La fonction fn_EEPStructureGetScale()

Regardons les trois arguments de cette fonction :

  1. 1er argument : Ar_ID_Lua ; comme d'habitude, il s'agit du numéro ID du modèle,
  2. 2ème argument : l'axe concerné ; Pour cela nous allons utiliser les constantes déjà existantes. Inutile de réinventer ce qui existe déjà !
  3. 3ème argument : la valeur à l'échelle 1 de l'axe concerné récupérée dans les tables des paramètres communs du modèle.

Voici le code de cette fonction :

Projet_principal.lua
-- *******************************************************************************
-- *                                                                             *
-- *  Cette fonction retourne la nouvelle dimension en mètres des structures     *
-- *  si les valeurs des échelles ont été modifiés                               *
-- *                                                                             *
-- *  Ar_Ar_ID_Lua = Nom lua de la structure (avec le signe #)                   *
-- *  Axe = Retourne la dimension selon l'axe demandé (x, y ou z)                *
-- *  Dimension = Dimension du modèle à l'échelle 1 (100 %)                      *
-- *                                                                             *
-- *******************************************************************************
function fn_EEPStructureGetScale(Ar_ID_Lua, Ar_Axe, Ar_Dimension)

	-- Ouvrir le fichier projet (modifier le chemin complet du projet à la ligne n° 10)
	local f = io.input( C_CHEMIN..gSt_NomProjet..".anl3" )

	-- La variable s récupère le texte du fichier projet
	local s = f:read( "*all" )

	-- Supprime le signe #
	local St_Ar_ID_Lua = string.match( Ar_ID_Lua, '%d+' )

	-- Rechercher dans le fichier projet, les valeurs X, Y, Z pour l'échelle
	--	de la structure ou de la marchandise à partir de son numéro Lua et enregistrer
	-- les informations dans la variable locale S_ValeurStructure
	local St_ValeurStructure = string.match( s, 'ImmoIdx="'..St_Ar_ID_Lua..'".-</Dreibein>' )

	-- Variable pour stocker les valeurs x ou y ou z selon le deuxième argument de la fonction
	local St_Valeur_Ech = nil

	if Ar_Axe == C.ROTATION_AXE_X then
			St_Valeur_Ech = string.match( St_ValeurStructure, '</Vektor>.+x="([%d.]+)".+Dir' )
			--print("St_Valeur_Ech X : ", fn_Round(St_Valeur_Ech, 2))
		elseif Ar_Axe == C.ROTATION_AXE_Y then
			St_Valeur_Ech = string.match( St_ValeurStructure, '</Vektor>.+y="([%d.]+)".+Nor' )
			--print("St_Valeur_Ech Y : ", fn_Round(St_Valeur_Ech, 2))
		elseif Ar_Axe == C.ROTATION_AXE_Z then
			St_Valeur_Ech = string.match( St_ValeurStructure, '</Vektor>.+z="([%d.]+)".+Bin' )
			--print("St_Valeur_Ech Z : ", fn_Round(St_Valeur_Ech, 2))
	end

	return fn_Round( Ar_Dimension * St_Valeur_Ech, 2 )

end

A la ligne n° 2044 se trouve l'en-tête de la fonction avec ses trois arguments entre parenthèses.

L'instruction Lua io.input à la ligne n° 2047 ouvre le fichier du projet utilisé pour les articles sur les rotations. Entre parenthèses figure le nom du chemin complet consigné dans la constante C_CHEMIN définie au début du script principal à la ligne n° 10. Ensuite la variable gSt_NomProjet contient le nom du projet suivi de l'extension des fichiers projets EEP .anl3. Les deux points .. de chaque côté de gSt_NomProjet ont pour but de concaténer la constante + la variable + l'extension pour former une chaine de caractères contigüe. Le tout est transféré dans la variable locale f.

Ci-dessous, la déclaration de ces éléments au début du script principal et les commentaires associés :

Déclaration constante et variable pour le chemin du projet
Projet_principal.lua
-- Constante pour le chemin d'accès au dossier du projet (A ajuster selon le cas)
-- Ne pas oublier de doubler l'anti-slash \\ dans le chemin d'accès sinon une erreur se produira !
C_CHEMIN = "E:\\Trend_FR\\Projets\\Portes\\Rotation_finale\\"
Projet_principal.lua
--[[ En préparation pour l'ouverture du fichier projet en cours dans EEP
	 Récupérer le nom du projet via la fonction lua EEPGetAnlName()
	 (EEPGetAnlName nécessite EEP17 plugin 1 sinon écrire en dur le nom du projet
	 dans la variable gSt_NomProjet sans rajouter d'anti-slash)
	]]
gSt_NomProjet = EEPGetAnlName()

Au final dans notre exemple, pour simplifier le chemin dans la variable f est égal à "E:\Trend_FR\Projets\Portes\Rotation_finale\Rotations.anl3".

La ligne N° 2050 transfère dans la variable locale s l'intégralité du contenu du fichier projet via l'instruction Lua read préfixée de la variable f: avec l'argument "*all" qui signifie "lire tout le texte du fichier".

La variable s peut maintenant être utilisée pour rechercher les valeurs d'échelles correspondantes du modèle concerné.

Ensuite la ligne n° 2053 a pour but du supprimer le signe # de l'argument dans la variable locale St_Ar_ID_Lua :

Projet_principal.lua
	-- Supprime le signe #
	local St_Ar_ID_Lua = string.match( Ar_ID_Lua, '%d+' )

Pourquoi ? car nous devons "nettoyer" l'argument et conserver uniquement le numéro ID sans le signe #. Plusieurs techniques sont possibles comme l'utilisation des fonctions Lua string.len ou string.sub mais il y a plus simple. Nous allons seulement utiliser la fonction Lua string.match qui signifie : retourner une sous-chaine à partir de la variable chaine Ar_ID_Lua passée en 1er argument à l'aide d'un pattern passé en 2ème argument. Un pattern qu'est-ce-que c'est ? encore un animal inconnu ? 😉 Un pattern n'est ni plus ni moins qu'un motif spécial entouré par des guillemets simples. Plusieurs motifs existent mais celui qui nous intéresse ici est %d.

La traduction de %d veut dire : seulement un chiffre de 0 à 9 ! tout autre caractère ne correspondant pas à un chiffre sera définitivement éliminé sans pitié ! Ok c'est bien, mais si l'ID de notre modèle contient plusieurs chiffres comme l'ID 101 par exemple ? Le signe + est là pour répondre à cette question. Le signe + veut dire : plus d'1 chiffre. Donc si Ar_ID_Lua = "#101", St_Ar_ID_Lua sera = à 101.

Ensuite nous allons passer à la ligne n° 2058 :

Projet_principal.lua
	-- Rechercher dans le fichier projet, les valeurs X, Y, Z pour l'échelle
	-- de la structure ou de la marchandise à partir de son numéro Lua et enregistrer
	-- les informations dans la variable locale S_ValeurStructure
	local St_ValeurStructure = string.match( s, 'ImmoIdx="'..St_Ar_ID_Lua..'".-</Dreibein>' )

La variable locale St_ValeurStructure récupère toutes les propriétés du modèle correspondant au n° ID dans le fichier projet.

Juste pour info, voici à quoi ressemble dans le fichier de notre projet EEP les propriétés de notre "mur-porte" avec l'ID 101 des articles précédents catégorisé en tant que structure immobilière :

Fichier du projet EEP Rotations.anl3
		<Immobile gsbname="\Immobilien\Ausstattung\Begrenzungen\Gl_Mauer_3_1gl_10m_RE1.3DM" Smoke="0" Fire="0" Light="0" ImmoIdx="101" LockEd="0">
			<Dreibein>
				<Vektor x="41000" y="-9999.997" z="0">Pos</Vektor>
				<Vektor x="3.000001" y="6.685082E-17" z="0">Dir</Vektor>
				<Vektor x="-1.114161E-17" y="0.4999915" z="0">Nor</Vektor>
				<Vektor x="0" y="0" z="1">Bin</Vektor>
			</Dreibein>
			<Modell/>
		</Immobile>

Le modèle utilisé ici dans notre exercice est un mur en briques avec le n° ID 4. Ainsi à la ligne n° 2058 nous retrouvons la fonction string.match pour rechercher dans la variable s (passée en premier argument) la propriété 'ImmoIdx' (index pour l'immobilier) avec le n° ID 4 jusqu'à la balise </Dreibein> :

Projet_principal.lua
local St_ValeurStructure = string.match( s, 'ImmoIdx="'..St_Ar_ID_Lua..'".-</Dreibein>' )

J'utilise les expressions irrégulières nommées aussi Regex dans le jargon informatique en combinaison avec la fonction string.match. Même si cela dépasse le cadre de notre article, je vais expliquer rapidement le deuxième argument de la fonction string.match :

  1. 'ImmoIdx=" ' : propriété ImmoIdx avec le signe = suivi du premier guillemet,
  2. ..St_Ar_ID_Lua.. : numéro ID du modèle avec la syntaxe des 2 points .. pour la concaténation,
  3. ' ".-</Dreibein>' : le deuxième guillemet après le numéro ID suivi d'un point. Avec les regex, le point signifie n'importe quel caractère, ensuite le signe moins veut dire le moins de caractère possible jusqu'à la balise </Dreibein>
  4. Et pour info, l'utilisation des guillemets simples s'impose car le numéro ID est déjà entouré par des guillemets doubles.

Bref, pour conclure, l'affichage de notre variable S_ValeurStructure retourne ceci :

Fichier du projet EEP Rotations.anl3
ImmoIdx="4" LockEd="0">
			<Dreibein>
				<Vektor x="22000" y="-10000" z="0">Pos</Vektor>
				<Vektor x="2" y="0" z="0">Dir</Vektor>
				<Vektor x="0" y="3" z="0">Nor</Vektor>
				<Vektor x="0" y="0" z="1">Bin</Vektor>
			</Dreibein>

A ce stade, nous avons isolé les propriétés et valeurs des facteurs d'échelle de notre mur en briques, nous allons pouvoir les extraire avec l'aide de notre fonction Lua string.match !

Passons maintenant à la ligne n° 2061 et la déclaration d'une variable locale nommée St_Valeur_Ech. Comme son nom l'indique, celle-ci va être utilisée pour récupérer la valeur du facteur d'échelle pour l'axe concerné.

Ensuite les tests débutent à la ligne n° 2063 avec comme condition le deuxième argument de la fonction selon l'axe demandé et nous allons commencer par l'axe X.

Si Ar_Axe est égal C.ROTATION_AXE_X alors la condition est vérifiée et vraie. Le programme passe directement à la ligne n° 2064.

Projet_principal.lua
	-- Variable pour stocker les valeurs x ou y ou z selon le deuxième argument de la fonction
	local St_Valeur_Ech = nil

	if Ar_Axe == C.ROTATION_AXE_X then
			St_Valeur_Ech = string.match( S_ValeurStructure, '</Vektor>.+x="([%d.]+)".+Dir' )
			--print("St_Valeur_Ech X : ", fn_Round(St_Valeur_Ech, 2))
		elseif Ar_Axe == C.ROTATION_AXE_Y then
			St_Valeur_Ech = string.match( S_ValeurStructure, '</Vektor>.+y="([%d.]+)".+Nor' )
			--print("St_Valeur_Ech Y : ", fn_Round(St_Valeur_Ech, 2))
		elseif Ar_Axe == C.ROTATION_AXE_Z then
			St_Valeur_Ech = string.match( S_ValeurStructure, '</Vektor>.+z="([%d.]+)".+Bin' )
			--print("St_Valeur_Ech Z : ", fn_Round(St_Valeur_Ech, 2))
	end

La fonction string.match extrait à l'intérieur de la variable St_ValeurStructure le facteur d'échelle de l'axe X. Cette fois-ci, le pattern est un peu plus complexe. Allez, j'explique quand même celui-ci et le même principe s'appliquera pour les deux autres :

  1. '</Vektor>.+x=" : commence la recherche à partir de la balise </Vektor jusqu'au premier x=". Résultat : </Vektor><Vektor x="
  2. ([%d.]+) : les parenthèses utilisées ici vont capturer le résultat de notre motif placé entre crochets. Nous retrouvons notre motif %d uniquement pour les chiffres suivi d'un point mais ici, ce point ne veut pas dire n'importe quel caractère. Non, il s'agit du point des chiffres décimaux. La distinction est faite car le point est placé entre les crochets. En dehors des crochets, le point signifierai effectivement n'importe quel caractère. Ensuite le signe + veut dire 1 ou plusieurs chiffres. Résultat : 2
  3. '".+Dir' : termine la recherche jusqu'à rencontrer le mot Dir. Le point et le signe + signifient tous les caractères jusqu'au mot Dir. Résultat : " y="0" z="0">Dir
Fichier du projet EEP Rotations.anl3
ImmoIdx="4" LockEd="0">
			<Dreibein>
				<Vektor x="22000" y="-10000" z="0">Pos</Vektor>
				<Vektor x="2" y="0" z="0">Dir</Vektor>
				<Vektor x="0" y="3" z="0">Nor</Vektor>
				<Vektor x="0" y="0" z="1">Bin</Vektor>
			</Dreibein>

Conclusion : le fait d'utiliser les parenthèses autour du motif %d nous a permis d'extraire uniquement la valeur de l'échelle X (dans notre exemple égale à 2) sinon si les parenthèses n'avaient pas été utilisées, toute la chaine </Vektor><Vektor x="2" y="0" z="0">Dir aurait été retournée dans la variable S_Valeur_Ech.

Le même principe s'applique pour les facteurs d'échelles Y et Z. Seuls respectivement les mots clés Nor et Bin sont utilisés à la place de Dir.

Pour résumer, j'ai repris les 3 lignes pour vous aider à mieux situer les valeurs (en rouge) dans les propriétés du modèle transférées dans la variable St_ValeurStructure :

  1. Ligne n° 4 : <Vektor x="2" y="0" z="0">Dir
  2. Ligne n° 5 : <Vektor x="0" y="3" z="0">Nor
  3. Ligne n° 6 : <Vektor x="0" y="0" z="1">Bin

Dans l'extrait du fichier Rotations.anl3 ci-dessus, la ligne n° 4 concerne l'échelle X = à 2, la n° 5 l'échelle Y = à 3 et la n° 6 l'échelle Z = à 1. Nous retrouvons bien les mêmes valeurs dans la fenêtre des propriétés du modèle :

Fenêtre des propriétés du mur en brique avec EEP et Lua pour les rotations à l'échelle 2

Ensuite la fonction se termine à la dernière ligne n° 2074 :

Projet_principal.lua
	return fn_Round( Ar_Dimension * St_Valeur_Ech, 2 )

Le programme retourne la valeur corrigée en multipliant la dimension du modèle à l'échelle 1 (argument Ar_Dimension) par la valeur de l'échelle (variable St_Valeur_Ech), le tout arrondi à deux décimales après la virgule avec la fonction fn_Round().

Il n'existe pas dans le langage Lua de fonction pour arrondir les nombres à l'entier inférieur ou supérieur. Qu'à cela ne tienne, j'ai créé la petite fonction personnalisée fn_Round() dont voici le code ci-dessous :

Projet_principal.lua
-- ********************************************************************************
-- *                                                                              *
-- *  Cette fonction arrondit les nombres selon un nombre variable de décimales   *
-- *                                                                              *
-- *  Ar_Nbr = Nombre à arrondir                                                  *
-- *  Ar_Dec = Nombre de décimales après la virgule                               *
-- *                                                                              *
-- ********************************************************************************
function fn_Round(Ar_Nbr, Ar_Dec)

  -- Variable local NDec (nombre de décimals)
  -- NDec est égal à 10 puissance (nombre de décimals récupéré dans l'argument Ar_Dec)
  -- Sinon si Ar_Dec n'était pas renseigné NDec serait égal à 1.
	local NDec = 10^( Ar_Dec or 0 )
	-- Déplace la virgule vers la droite avec la valeur NDec
	Ar_Nbr = Ar_Nbr * NDec

  -- Si Ar_Nbr est supérieur ou égal à 0, math.floor arrondi à l'entier inférieur après avoir ajouté 0.5
  -- Sinon si Ar_Nbr est négatif math.ceil arrondi à l'entier supérieur après avoir soustrait 0.5.
	if Ar_Nbr >= 0 then Ar_Nbr = math.floor( Ar_Nbr + 0.5 ) else Ar_Nbr = math.ceil( Ar_Nbr - 0.5 ) end

  -- le résultat est divisé par le nombre de décimal afin de replacer la virgule à sa position d'origine
	return Ar_Nbr / NDec

end

La ligne n° 2094 retourne le nombre arrondi à l'entier inférieur ou supérieur selon le cas avec le nombre de décimales demandé dans l'argument Ar_Dec.

Revenons une dernière fois à la ligne n° 2074 dans la fonction fn_EEPStructureGetScale() :

Projet_principal.lua
	return fn_Round( Ar_Dimension * St_Valeur_Ech, 2 )

L'appel de la fonction fn_Round() est vivement recommandée car les facteurs d'échelles dans la fenêtre des propriétés du modèle n'accepte que deux chiffres après la virgule. Ceci permet de maintenir une cohérence entre les calculs. Une fois la valeur retournée, le programme revient sous la ligne n° 1305 dans la fonction fn_Operation().

Après la fonction fn_EEPStructureGetScale()

Nous venons d'étudier la fonction fn_EEPStructureGetScale() utilisée pour calculer et retourner les dimensions correctes en cas de modification du facteur d'échelle. A ce stade, une question peut se poser : "Et si les facteurs d'échelle ne sont pas modifiés ?". Et bien la fonction retourne tout simplement les dimensions à l'échelle 1.

Reprenons à partir de la ligne n° 1307 :

Projet_principal.lua
	print("\ngTb_Ech_Dimension_X : ", gTb_Ech_Dimension_X[Ar_ID_Lua])
	print("gTb_Ech_Dimension_Y : ", gTb_Ech_Dimension_Y[Ar_ID_Lua])
	print("gTb_Ech_Dimension_Z : ", gTb_Ech_Dimension_Z[Ar_ID_Lua], "\n")

Les lignes n° 1307 à 1309 impriment dans la fenêtre d'évènements les dimensions des modèles avec les valeurs d'échelles ajustées selon le cas. Vous pouvez commentez ces lignes si vous ne souhaitez pas les imprimer.

Les tests conditionnels pour les corrections

Passons maintenant aux tests conditionnels à partir de la ligne n° 1311 :

Projet_principal.lua
		if gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_CENTRE then

				gTb_Corr_Pos_X[Ar_ID_Lua] = ( gTb_Long_X_Ech1[Ar_ID_Lua] / 2 ) + ( ( gTb_Ech_Dimension_X[Ar_ID_Lua] - gTb_Long_X_Ech1[Ar_ID_Lua] ) / 2 )
				--print( "gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_CENTRE : ", gTb_Corr_Pos_X[Ar_ID_Lua] )

				gTb_Corr_Pos_Y[Ar_ID_Lua] = ( gTb_Larg_Y_Ech1[Ar_ID_Lua] / 2 ) + ( ( gTb_Ech_Dimension_Y[Ar_ID_Lua] - gTb_Larg_Y_Ech1[Ar_ID_Lua] ) / 2 )
				--print( "gTb_Corr_Pos_Y[Ar_ID_Lua] C.ROTATION_ORIGINE_CENTRE : ", gTb_Corr_Pos_Y[Ar_ID_Lua] )

			elseif gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_GAUCHE then

				if Ar_Pos_Pt_Rot == C.ROT_Y_A_DROITE or 
						Ar_Pos_Pt_Rot == C.ROT_Z_COIN_AVANT_DROIT or
							Ar_Pos_Pt_Rot == C.ROT_Z_MILIEU_DROIT or
								Ar_Pos_Pt_Rot == C.ROT_Z_COIN_ARRIERE_DROIT then

						gTb_Corr_Pos_X[Ar_ID_Lua] = gTb_Ech_Dimension_X[Ar_ID_Lua]
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

					else

						-- Par déduction, ici Ar_Pos_Pt_Rot = toutes les positions de rotations vers la gauche
						gTb_Corr_Pos_X[Ar_ID_Lua] = 0
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

				end

				gTb_Corr_Pos_Y[Ar_ID_Lua] = gTb_Ech_Dimension_Y[Ar_ID_Lua]  / 2
				--print("gTb_Corr_Pos_Y[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_Y[Ar_ID_Lua])

			elseif gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_DROITE then

				if Ar_Pos_Pt_Rot == C.ROT_Y_A_GAUCHE or 
						Ar_Pos_Pt_Rot == C.ROT_Z_COIN_AVANT_GAUCHE or
							Ar_Pos_Pt_Rot == C.ROT_Z_MILIEU_GAUCHE or
								Ar_Pos_Pt_Rot == C.ROT_Z_COIN_ARRIERE_GAUCHE then

						gTb_Corr_Pos_X[Ar_ID_Lua] = gTb_Ech_Dimension_X[Ar_ID_Lua]
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

					else

						-- Par déduction, ici Ar_Pos_Pt_Rot = toutes les positions de rotations vers la droite
						gTb_Corr_Pos_X[Ar_ID_Lua] = 0
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

				end

				gTb_Corr_Pos_Y[Ar_ID_Lua] = gTb_Ech_Dimension_Y[Ar_ID_Lua]  / 2
				--print("gTb_Corr_Pos_Y[Ar_ID_Lua] C.ROTATION_ORIGINE_DROITE : ", gTb_Corr_Pos_Y[Ar_ID_Lua])

		end

		-- gTb_Corr_Pos_Z[Ar_ID_Lua] ne concerne que la rotation Y à partir du bord supérieur gauche ou droit
		gTb_Corr_Pos_Z[Ar_ID_Lua] = gTb_Ech_Dimension_Z[Ar_ID_Lua]

Les plus observateurs d'entre-vous ne manqueront pas de faire le rapprochement entre les trois rotations d'origine : au centre, à gauche et à droite.

Je vais décortiquer les calculs des trois axes de positions pour la rotation d'origine située au centre.

Corrections des axes X et Y pour la rotation d'origine située au centre

Si la rotation d'origine est située au centre, deux actions doivent être menées :

  1. Les dimensions du modèle doivent être divisées par 2,
  2. La modification éventuelle des facteurs d'échelle impose la correction des dimensions du modèle.

Un petit dessin pour comprendre :

Dessin pour calcul des dimensions si rotation d'origine au centre dans EEP
Translation du point de rotation au centre vers le côté gauche ou droit
Projet_principal.lua
if gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_CENTRE then

	  gTb_Corr_Pos_X[Ar_ID_Lua] = ( gTb_Long_X_Ech1[Ar_ID_Lua] / 2 ) + ( ( gTb_Ech_Dimension_X[Ar_ID_Lua] - gTb_Long_X_Ech1[Ar_ID_Lua] ) / 2 )
  1. Le premier calcul entre parenthèses divise par 2 la longueur sur l'axe X à l'échelle 1. Cette "demi-longueur" sera prise en compte ultérieurement dans les calculs,
  2. Le deuxième calcul entre parenthèses après le signe + récupère la longueur calculée si modification du facteur d'échelle.

Prenons un exemple concret sans modification du facteur d'échelle et la longueur initiale de 40 mètres de notre modèle ID n° 4 :

  • Le premier calcul entre parenthèses divise par deux la longueur sur l'axe X à l'échelle 1 : 40 / 2 = 20 mètres,
  • Le deuxième calcul entre parenthèses après le signe + se décompose comme suit :
    1. gTb_Ech_Dimension_X[Ar_ID_Lua] = 40 (résultat de notre fonction fn_EEPStructureGetScale)
    2. gTb_Long_X_Ech1[Ar_ID_Lua] = 40 (valeur située dans la table des paramètres communs du modèle)
  • Selon la priorité des parenthèses : gTb_Ech_Dimension_X[Ar_ID_Lua] - gTb_Long_X_Ech1[Ar_ID_Lua] = 0 (40 - 40). Ensuite le résultat divisé par deux est égal à 0,
  • Le premier calcul est additionné avec le deuxième calcul et nous donne comme résultat final : 20 mètres (20 + 0).

Pour terminer, le résultat transféré dans la table gTb_Corr_Pos_X[Ar_ID_Lua] est égal à 20 mètres et cette table sera utilisée par la suite dans les calculs selon le type de rotation demandée.

Prenons maintenant un exemple concret avec modification du facteur d'échelle égal à 2 et la longueur initiale de 40 mètres de notre modèle ID n° 4 :

Projet_principal.lua
if gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_CENTRE then

	  gTb_Corr_Pos_X[Ar_ID_Lua] = ( gTb_Long_X_Ech1[Ar_ID_Lua] / 2 ) + ( ( gTb_Ech_Dimension_X[Ar_ID_Lua] - gTb_Long_X_Ech1[Ar_ID_Lua] ) / 2 )
  • Le premier calcul entre parenthèses divise toujours par deux la longueur sur l'axe X à l'échelle 1 : 40 / 2 = 20 mètres,
  • Le deuxième calcul entre parenthèses après le signe + se décompose comme suit :
    1. gTb_Ech_Dimension_X[Ar_ID_Lua] = 80 (résultat de notre fonction fn_EEPStructureGetScale)
    2. gTb_Long_X_Ech1[Ar_ID_Lua] = 40 (valeur située dans la table des paramètres communs du modèle)
  • Selon la priorité des parenthèses : gTb_Ech_Dimension_X[Ar_ID_Lua] - gTb_Long_X_Ech1[Ar_ID_Lua] = 40 (80 - 40). Ensuite le résultat divisé par deux est égal à 20,
  • Le premier calcul est additionné avec le deuxième calcul et nous donne comme résultat final : 40 mètres (20 + 20).

Pour terminer, le résultat transféré dans la table gTb_Corr_Pos_X[Ar_ID_Lua] est égal à 40 mètres et cette table sera utilisée par la suite dans les calculs selon le type de rotation demandée. Nous pourrions énoncer le calcul autrement sachant que notre modèle sur l'axe X mesure 40 mètres multipliés par 2 = 80 mètres. Comme nous sommes sur une rotation de base située au centre, 80 / 2 = 40 mètres. Nous retrouvons bien nos 40 mètres et cette valeur correspond bien à la "demi-mesure" de notre modèle.

A la ligne n° 1316, le calcul pour l'axe Y (dont le résultat est envoyé dans la table gTb_Corr_Pos_Y[Ar_ID_Lua]) respecte strictement la même logique applicable pour l'axe X :

Projet_principal.lua
gTb_Corr_Pos_Y[Ar_ID_Lua] = ( gTb_Larg_Y_Ech1[Ar_ID_Lua] / 2 ) + ( ( gTb_Ech_Dimension_Y[Ar_ID_Lua] - gTb_Larg_Y_Ech1[Ar_ID_Lua] ) / 2 )
Corrections des axes X et Y pour la rotation d'origine située à gauche

Pour la rotation d'origine située à gauche, les opérations sont différentes et plus simples par rapport à la rotation d'origine située au centre.

Projet_principal.lua
			elseif gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_GAUCHE then

				if Ar_Pos_Pt_Rot == C.ROT_Y_A_DROITE or 
						Ar_Pos_Pt_Rot == C.ROT_Z_COIN_AVANT_DROIT or
							Ar_Pos_Pt_Rot == C.ROT_Z_MILIEU_DROIT or
								Ar_Pos_Pt_Rot == C.ROT_Z_COIN_ARRIERE_DROIT then

						gTb_Corr_Pos_X[Ar_ID_Lua] = gTb_Ech_Dimension_X[Ar_ID_Lua]
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

					else

						-- Par déduction, ici Ar_Pos_Pt_Rot = toutes les positions de rotations vers la gauche
						gTb_Corr_Pos_X[Ar_ID_Lua] = 0
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

				end

				gTb_Corr_Pos_Y[Ar_ID_Lua] = gTb_Ech_Dimension_Y[Ar_ID_Lua]  / 2
				--print("gTb_Corr_Pos_Y[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_Y[Ar_ID_Lua])

Pour l'axe X, le test se porte uniquement sur la rotation souhaitée. Si nous demandons une rotation sur le côté droit, la dimension sur l'axe X est égale à sa dimension totale afin de "déplacer" ou translater le point de rotation sur le côté droit. Rappelez-vous ce petit dessin :

Dessin déplacement axe de rotation avec Lua et EEP
Translation du point de rotation gauche vers le côté droit

Cette valeur est transférée dans la table gTb_Corr_Pos_X[Ar_ID_Lua] et prend en compte la modification éventuelle du facteur d'échelle. A l'inverse, pour toutes les rotations souhaitées à gauche, la valeur de gTb_Corr_Pos_X[Ar_ID_Lua] est égale à 0 et correspond au point de rotation d'origine de base.

Pour l'axe Y, la valeur de gTb_Ech_Dimension_Y[Ar_ID_Lua] est divisée par deux. En effet, le point de rotation d'origine est toujours situé au centre sur l'axe Y.

Corrections des axes X et Y pour la rotation d'origine située à droite

Pour la rotation d'origine située à droite, le même principe pour la rotation d'origine située au gauche est appliqué :

Projet_principal.lua
			elseif gTb_Rot_Origine[Ar_ID_Lua] == C.ROTATION_ORIGINE_DROITE then

				if Ar_Pos_Pt_Rot == C.ROT_Y_A_GAUCHE or 
						Ar_Pos_Pt_Rot == C.ROT_Z_COIN_AVANT_GAUCHE or
							Ar_Pos_Pt_Rot == C.ROT_Z_MILIEU_GAUCHE or
								Ar_Pos_Pt_Rot == C.ROT_Z_COIN_ARRIERE_GAUCHE then

						gTb_Corr_Pos_X[Ar_ID_Lua] = gTb_Ech_Dimension_X[Ar_ID_Lua]
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

					else

						-- Par déduction, ici Ar_Pos_Pt_Rot = toutes les positions de rotations vers la droite
						gTb_Corr_Pos_X[Ar_ID_Lua] = 0
						--print("gTb_Corr_Pos_X[Ar_ID_Lua] C.ROTATION_ORIGINE_GAUCHE : ", gTb_Corr_Pos_X[Ar_ID_Lua])

				end

				gTb_Corr_Pos_Y[Ar_ID_Lua] = gTb_Ech_Dimension_Y[Ar_ID_Lua]  / 2
				--print("gTb_Corr_Pos_Y[Ar_ID_Lua] C.ROTATION_ORIGINE_DROITE : ", gTb_Corr_Pos_Y[Ar_ID_Lua])

Si une rotation souhaitée est demandée à gauche, on effectue une translation du point de rotation sur l'axe X comme le montre ce petit dessin :

Dessin déplacement axe de rotation avec Lua et EEP
Translation du point de rotation droit vers le côté gauche

Pour l'axe Y, la dimension enregistrée dans la table gTb_Ech_Dimension_Y[Ar_ID_Lua] est divisée par deux. En effet, le point de rotation d'origine est situé au centre sur l'axe Y.

La correction de l'axe Z

Voici le code pour la correction de l'axe Z :

Projet_principal.lua
	-- gTb_Corr_Pos_Z[Ar_ID_Lua] ne concerne que la rotation Y à partir du bord supérieur gauche ou droit
	gTb_Corr_Pos_Z[Ar_ID_Lua] = gTb_Ech_Dimension_Z[Ar_ID_Lua]

La position Z ne concerne que la rotation Y à partir du côté supérieur gauche ou droit. Nous aurons l'occasion d'y revenir lorsque nous aborderons la rotation Y.

Le résultat final

Démarrons la locomotive et regardons la scène :

Gif pour la rotation Z sous EEP à l'échelle 2

Et bien que se passe t'il ? malgré nos calculs, le point de rotation n'est toujours pas fixé et aligné sur le côté gauche du modèle. Pourquoi ?

Nous avons utilisé notre fonction personnalisée fn_EEPStructureGetScale(). Cette fonction n'existe pas dans EEP à l'heure où j'écris ces lignes (c'est-à-dire jusqu'au plugin 3 pour EEP17). Pour effectuer la rotation au bon endroit, il faut penser à enregistrer le projet EEP afin que les facteurs d'échelles soient lus correctement par notre fonction fn_EEPStructureGetScale().

Une fois le projet enregistré, voici le résultat :

Gif pour la rotation Z sous EEP à l'échelle 2 projet enregistré

Le point de rotation est désormais positionné au bon endroit comme l'indique le repère rouge et blanc sur le côté gauche. La correction est automatique !

Un autre exemple

Nous venons de découvrir un exemple avec le mur en brique ID n° 4 dont la rotation d'origine est située au centre. Dans l'article suivant, nous découvrirons les calculs pour ce point de rotation.

Pour l'instant, nous allons reprendre notre modèle ID101 avec ouverture sur le côté droit exactement comme dans l'article précédent mais cette fois-ci avec la modification des trois facteurs d'échelle comme ceci :

Propriétés du mur en béton avec échelles modifiées dans EEP avec Lua
Propriétés du modèle ID101
  1. Echelle X : 4.48,
  2. Echelle Y : 2.57,
  3. Echelle Z : 2.39.

Notre modèle affiché en mode 3D après avoir cliqué sur le bouton OK :

Mu mur en béton en 3D avec échelles modifiées dans EEP avec Lua
Important : Pensez toujours à enregistrer le projet si vous modifier les échelles pour la lecture correcte des facteurs d'échelles via la fonction personnalisée fn_EEPStructureGetScale().

Le poteau blanc est là comme repère pour le point de rotation. Dans cet exemple, nous allons laisser de côté les calculs (déjà abordés dans l'article précédent) pour nous intéresser uniquement sur la modification des facteurs d'échelles.

Je vais afficher dans la fenêtre d'évènements les valeurs (en mètres) des tables gTb_Ech_Dimension_X, gTb_Ech_Dimension_Y et gTb_Ech_Dimension_Z lors des opérations ouverture-fermeture :

Fenêtre d'évènements EEP pour le modèle ID101
Fenêtre d'évènements pour le modèle ID101

Petit rappel des paramètres communs du modèle concerné (ici le mur en béton) concernant les dimensions à l'échelle 1:

ID_Modeles.lua
-- Paramètres communs pour le mur en béton
function M.ImmoBetonRE1(Ar_ID_Lua)

	-- La longueur du mur Ar_ID_Lua à l'échelle 1 est = à 10.5 mètres
	gTb_Long_X_Ech1[Ar_ID_Lua] = 10.5
	-- La largeur du mur Ar_ID_Lua à l'échelle 1 est = à 6 mètres
	gTb_Larg_Y_Ech1[Ar_ID_Lua] = 6
	-- La hauteur du mur Ar_ID_Lua à l'échelle 1 est = à 8 mètres
	gTb_Haut_Z_Ech1[Ar_ID_Lua] = 8
	--[[ Variable pour stocker la valeur calculée des rotations
		  à chaque itération de la boucle while ]]
	gTb_Rot_Calcul[Ar_ID_Lua] = 0
	
	gTb_Rot_Origine[Ar_ID_Lua] = C.ROTATION_ORIGINE_GAUCHE

end

Les résultats obtenus après les calculs via notre fonction fn_EEPStructureGetScale() sont :

  1. Pour l'axe X : 47.04 = facteur d'échelle 4.48 x longueur 10.5 = 47.04 mètres,
  2. Pour l'axe Y : 15.42 = facteur d'échelle 2.57 x longueur 6 = 15.42 mètres,
  3. Pour l'axe Z : 19.12 = facteur d'échelle 2.39 x longueur 8 = 19.12 mètres.

J'ai choisi des valeurs composées de chiffres décimaux pour revenir sur un aspect particulier dans la fonction fn_EEPStructureGetScale().

Rappelez-vous le motif ([%d.]+) entre parenthèses :

St_Valeur_Ech = string.match( St_ValeurStructure, '</Vektor>.+x="([%d.]+)".+Dir' )

Entre les crochets, le motif %d veut dire tous les chiffres de 0 à 9 et le point après le d correspond au point décimal. Le signe + après le dernier crochet indique à la fonction string.match de retourner tous les chiffres possibles compris entre les deux guillemets avant et après les parenthèses. Si ce signe + n'était pas utilisé, la fonction serait incapable de capturer le facteur d'échelle qui plus est, si celui-ci comporte deux chiffres après la virgule comme dans notre exemple.

Sans l'utilisation des parenthèses, tous les caractères entre </Vektor> et Dir seraient transférés dans la variable St_Valeur_Ech. Les parenthèses jouent ici le rôle d'un filtre pour capturer et retourner uniquement les informations nécessaires comme la valeur du facteur d'échelle et rien d'autre.

Connaitre les dimensions des modèles

Nous l'avons vu, il est primordial de connaitre la dimension des modèles à l'échelle de base, c'est-à-dire à l'échelle 1. Mais comment faire ? EEP (jusqu'à la version 17 plugin 3) nous offre aucune fonction pour retourner les mesures des modèles.

Pour les trois dimensions c'est assez facile. Il suffit dans un premier temps de bien vérifier les propriétés de la mise à l'échelle fixées à 1 pour le modèle concerné :

Modèle à l'échelle 1 pour mesure dans fenêtre 2D avec EEP
Echelle 1 impérative !

Ensuite dans la fenêtre 2D, nous allons ouvrir le menu Outils et choisir la commande Paramètres de la grille pour afficher la petite fenêtre suivante :

Fenêtre des paramètres de la grille dans EEP

Pour nous faciliter le travail, nous allons utiliser des carrés avec un espacement d'un mètre de côté sur les axes X et Y. Après avoir fermer cette petite fenêtre, cliquez sur le bouton pour afficher la grille situé tout en bas à gauche dans la petite barre d'outils dans la fenêtre 2D :

Grille pour mesurer un modèle dans la fenêtre 2D avec EEP
Afficher la grille

Une fois la grille affichée, mesurer un modèle devient un jeu d'enfant :

Affichage grille du modèle pour mesures avec EEP
Affichage de la grille en mode 2D

Pour un parfait alignement sur la grille, définissez une valeur entière pour la position X et Y, ici dans notre exemple X est égal à -202 et Y est égal à 0. Vous remarquerez la longueur du modèle égale à 10.5 alors que le nom Lua (dans la fenêtre des propriétés) indique 10 mètres.

Nous connaissons maintenant les valeurs X et Y, il nous manque encore la valeur Z. Pour la récupérer, nous sommes obligés d'afficher notre modèle en 3D et d'activer la grille 3D en cliquant sur le bouton dans la petite barre d'outil en bas à gauche :

Affichage grille en 3D du modèle pour mesures avec EEP
Affichage de la grille en mode 3D

Il suffit juste d'ajuster la valeur Espacement Z dans la fenêtre des paramètres de la grille pour trouver la bonne dimension. Pour certains modèles, cela peut paraître fastidieux mais en l'absence de fonctions dédiées, il n'y a pas d'autre alternative.

Pour résumer, notre modèle mesure 10.5 mètres de longueur sur 6 mètres de largeur et 8 mètres en hauteur. Ceci explique pourquoi nous avons exactement ces mêmes valeurs dans la fonction des paramètres communs du modèle aux lignes n° 2065, 2067 et 2069:

Fonctions M.ImmoBetonRE1(Ar_ID_Lua)
ID_Modeles.lua
-- =====================================================================
-- =                                                                   =
-- =   Modèle : Mur en béton (Paroi de la voie) du constructeur RE1    =	
-- =   M.ImmoBetonRE1 concerne les modèles avec les ID :               =
-- =   20, 21, 23, 25, 19, 39, 63, 64, 65, 100, 101, 102, 112, 113     =
-- =                                                                   =
-- =====================================================================

-- Paramètres communs pour le mur en béton
function M.ImmoBetonRE1(Ar_ID_Lua)

	-- La longueur du mur Ar_ID_Lua à l'échelle 1 est = à 10.5 mètres
	gTb_Long_X_Ech1[Ar_ID_Lua] = 10.5
	-- La largeur du mur Ar_ID_Lua à l'échelle 1 est = à 6 mètres
	gTb_Larg_Y_Ech1[Ar_ID_Lua] = 6
	-- La hauteur du mur Ar_ID_Lua à l'échelle 1 est = à 8 mètres
	gTb_Haut_Z_Ech1[Ar_ID_Lua] = 8
	--[[ Variable pour stocker la valeur calculée des rotations
		  à chaque itération de la boucle while ]]
	gTb_Rot_Calcul[Ar_ID_Lua] = 0
	
	gTb_Rot_Origine[Ar_ID_Lua] = C.ROTATION_ORIGINE_GAUCHE

end

Une fois récupérées les valeurs des échelles égales à 1, vous pouvez modifier votre modèle comme bon vous semble. Le script calculera automatiquement les bonnes valeurs comme nous l'avons vu plus haut dans cet article.

Note : Les dimensions X, Y et Z à l'échelle 1 sont inscrites en binaire dans les fichiers des modèles avec l'extension *.3dm et non pas en clair dans le fichier *.anl3 comme les valeurs pour les échelles. Récupérer ces valeurs est tout à fait possible mais pour des raisons de légalité, je ne peux pas vous présenter la solution par le biais de fonctions personnalisées.

Conclusion

Nous voici arrivé à la fin de cet article. Nous avons appris comment gérer les modifications éventuelles des facteurs d'échelles pour conserver le point de rotation souhaité à la bonne place. Nous avons vu également comment mesurer les modèles utilisés pour récupérer les valeurs X, Y et Z à l'échelle 1.

Le prochain article va nous pousser plus loin dans la rotation Z mais avec d'autres modèles et d'autres paramètres avant d'aborder les rotations Y et X !

Je vous remercie de m'avoir suivi jusqu'ici et je vous dis à très bientôt !

Merci d'avoir lu cet article. Si vous avez des questions ou des suggestions, n’hésitez pas à nous en faire part en bas de cette page en commentaires.

Amusez-vous à lire un autre article. A bientôt !

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
0 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Retour en haut