/*
* MathGraph32 Javascript : Software for animating online dynamic mathematics figures
* https://www.mathgraph32.org/
* @Author Yves Biton (yves.biton@sesamath.net)
* @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
*/
import NatObj from '../types/NatObj'
import NatCal from '../types/NatCal'
import Complexe from '../types/Complexe'
import Pointeur from '../types/Pointeur'
import StyleEncadrement from '../types/StyleEncadrement'
import { cens, chaineNombre, codeLatexFracCont, decompPrim, fracCont, MAX_VALUE, pgcd, zero, zero13 } from '../kernel/kernel'
import CAffLiePt from './CAffLiePt'
import CCommentaire from './CCommentaire'
import CListeObjets from './CListeObjets'
import Nat from '../types/Nat'
import $ from 'jquery'
export default CLatex
/**
* Classe représentant un affichage LaTeX sur la figure.
* @constructor
* @extends CCommentaire
* @param {CListeObjets} listeProprietaire La liste propriétaire.
* @param {CImplementationProto} impProto null ou la cosntruction ppropriétaire.
* @param {boolean} estElementFinal true si l'objet est un élément final de construction.
* @param {Color} couleur La coileur d'écriture
* @param {number} xNom L'abscisse d'affichage.
* @param {number} yNom L'ordonnée d'affichage.
* @param {number} decX Décalage horizontal d'affichage.
* @param {number} decY Décalage vertical d'affichage.
* @param {boolean} masque true si l'objet est masqué.
* @param {CPt} pointLie null si l'affichage est libre ou pointe sur le point auquel il est lié.
* @param {number} taillePolice Donne la taille de la police utilisée.
* @param {number} encadrement entier pour le style d'encadrement (0, 1 ou 2, voir CAffLiePt).
* @param {boolean} effacementFond true si le fond doit être effacé avant écritrue.
* @param {Color} couleurFond La couleur de fond.
* @param {number} alignementHorizontal 0 pour alignement gauche, 1 pour centre, 2 pour droite.
* @param {number} alignementVertical 0 pour alignement vers le haut, 1 pour centré, 2 pour bas.
* @param {string} chaineCommentaire Contient le code LaTeX.
* @param {CValeurAngle} angText L'angle du texte par rapport à l'horizontale
* @param {boolean} fixed true si l'affichage est punaisé et ne peut pas être capturé à la souris
* @returns {CLatex}
*/
function CLatex (listeProprietaire, impProto, estElementFinal, couleur, xNom, yNom,
decX, decY, masque, pointLie, taillePolice, encadrement, effacementFond, couleurFond, alignementHorizontal,
alignementVertical, chaineCommentaire, angText, fixed) {
if (arguments.length === 1) CCommentaire.call(this, listeProprietaire)
else {
CCommentaire.call(this, listeProprietaire, impProto, estElementFinal, couleur, xNom, yNom,
decX, decY, masque, pointLie, taillePolice, encadrement, effacementFond, couleurFond, alignementHorizontal,
alignementVertical, chaineCommentaire, angText, fixed)
this.chaineCommentaire = chaineCommentaire
}
// Spécial JavaScript : chaineAffichee = contiendra la chaîne utilisée lors de l'affichage précédent.
// Si c'est la même, update ne fera pas appel à createg mais on changera simplement des coordonnées d'affichage du composant.
this.chaineAffichee = ''
// this.div = null // Supprimé version 6.4.8
}
CLatex.prototype = new CCommentaire()
CLatex.prototype.constructor = CLatex
CLatex.prototype.superClass = 'CCommentaire'
CLatex.prototype.className = 'CLatex'
function codeErreur (code) {
return '\\textcolor{red}{\\text{' + code + ' error}}'
}
// Modification version 8.7.3 : on passe un troisième paramètre impProto seulement dans le cas
// où on appelle getClone depuis CImplementationProto.prototype.implemente sur un objet qui
// a été obtenu par proto.getClone où proto est un CPrototype
CLatex.prototype.getClone = function (listeSource, listeCible, impProto = null) {
const ind1 = listeSource.indexOf(this.pointLie)
const ind2 = listeSource.indexOf(this.impProto)
const angTextClone = this.angText.getClone(listeSource, listeCible)
const ptelb = new CLatex(listeCible, listeCible.get(ind2, 'CImplementationProto'),
this.estElementFinal, this.couleur, this.xNom, this.yNom, this.decX, this.decY, this.masque,
listeCible.get(ind1, 'CPt'), this.taillePolice, this.encadrement,
this.effacementFond, this.couleurFond, this.alignementHorizontal,
this.alignementVertical, this.chaineCommentaire, angTextClone, this.fixed)
if (impProto) ptelb.impProto = impProto
ptelb.listValDynUsed = new CListeObjets(listeCible.uniteAngle, listeCible.pointeurLongueurUnite)
if (listeCible.className !== 'CPrototype') ptelb.determineDependances()
// Ligne suivante nécessaire car utilisé pour les exportations tikz
ptelb.id = this.id
return ptelb
}
CLatex.prototype.getNature = function () {
return NatObj.NLatex
}
CLatex.prototype.setClone = function (ptel) {
CAffLiePt.prototype.setClone.call(this, ptel)
this.chaineLatex = ptel.chaineLatex
}
CLatex.prototype.rendChaineAffichage = function () {
return this.chaineLatex
}
/**
* Fonction déterminant quels sont les calculs ou fonctions dont le commentaire dépend de façon dynamique.
* @param indiceReel Si présent c'est qu'on est en train d'utiliser un commentaire
* dans une boîte de dialogue d'aperçu et c'est alors l'indice du vrai commentaire qu'on est en train d'éditer
*/
CLatex.prototype.determineDependances = function (indiceReel = -1) {
let indicecommentaire, jdeb, j, indparf, ch, st, nomvaleur, pValeur, nomvaleur2, pValeur2
const chaineAAnalyser = this.chaineCommentaire.replace(/ /g, '')
this.listValDynUsed.retireTout()
// Quand on recherche si c'est bien le nom d'une valeur valide
// Il ne faut pas que la valeur ait été définie après l'affichage de valeur
let estDansListe = true
if (indiceReel !== -1) indicecommentaire = indiceReel
else indicecommentaire = this.listeProprietaire.indexOf(this)
if (indicecommentaire === -1) {
indicecommentaire = this.listeProprietaire.longueur() - 1
estDansListe = false // Le LaTex est en train d'être lu et n'est pas encore dans la liste
}
// On examine la chaine à la recherche de #Val(
const len = chaineAAnalyser.length
// Ajout version 6.7 : Traitement des codes \ValFrac qui renvoie le code LaTeX de la fraction continue de l'argument à 10^(-12) près
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\ValFrac{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 9)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 9, indparf).trim()
// On retire les éventuels espaces de cete chaine
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
// On recherche si c'est bien le nom d'une valeur valide
// Il ne faut pas que la valeur ait été définie après l'affichage de valeur
// Très important : quand determineDependances est appelé
// par getClone() de CCommentaire, le commentaire n'a pas encoré été rajouté
// à la liste clone et ainsi indiceCommentaire renvoie -1.
// dans ce cas, indiceCommentaire doit valoir le nombre d'éléments actuels
// de la liste clone qui le possède
pValeur = this.pointeur(NatCal.NTteValPourComDynSaufFoncSaufComp, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\Val{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 5)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 5, indparf).trim()
// On retire les éventuels espaces de cete chaine
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
// On recherche si c'est bien le nom d'une valeur valide
// Il ne faut pas que la valeur ait été définie après l'affichage de valeur
// Très important : quand determineDependances est appelé
// par getClone() de CCommentaire, le commentaire n'a pas encoré été rajouté
// à la liste clone et ainsi indiceCommentaire renvoie -1.
// dans ce cas, indiceCommentaire doit valoir le nombre d'éléments actuels
// de la liste clone qui le possède
// Modifié version 4.7.2
// CValDyn pValeur = pointeurValeurOuFonction(nomvaleur,indicecommentaire);
pValeur = this.pointeur(NatCal.NTteValPourComDynSaufFonc, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
j = indparf + 1
}
}
}
}
// Version 7.3 : On rajoute un code LaTeX \Decomp qui donne le décomposition en produit de facteurs
// premiers d'un entier supérieur ou égal à 2 et\DecompFull qui fait la même chose sans exposant
// en répétant les facteurs premiers
const tab = ['\\DecompFull{', '\\Decomp{']
for (let k = 0; k < 2; k++) {
j = 0
while (((jdeb = chaineAAnalyser.indexOf(tab[k], j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
const decal = tab[k].length // La longueur de la chaîne recherchée
indparf = chaineAAnalyser.indexOf('}', jdeb + decal)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Decomp( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + decal, indparf).trim()
// On retire les éventuels espaces de cete chaine
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
// On recherche si c'est bien le nom d'une valeur valide
// Il ne faut pas que la valeur ait été définie après l'affichage de valeur
// Très important : quand determineDependances est appelé
// par getClone() de CCommentaire, le commentaire n'a pas encoré été rajouté
// à la liste clone et ainsi indiceCommentaire renvoie -1.
// dans ce cas, indiceCommentaire doit valoir le nombre d'éléments actuels
// de la liste clone qui le possède
pValeur = this.pointeur(NatCal.NTteValRPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
j = indparf + 1
}
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\For{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 5)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 5, indparf).trim()
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\Calc{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 6)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 6, indparf).trim()
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
j = indparf + 1
}
}
}
}
// Version 6.7 : Traitement des codes \ForSimpFrac
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\ForSimpFrac{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 13)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 13, indparf).trim()
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\ForSimp{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 9)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 9, indparf).trim()
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\ForRep{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 8)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 8, indparf).trim()
// On sépare cette chaine avec les virgules
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\CalcSimp{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 10)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \Val( et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 10, indparf).trim()
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
j = indparf + 1
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\FracRed{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 9)
if (indparf === -1) break
else {
// On crée une chaine formé de ce qu'il y a entre \FracRed{ et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 9, indparf).trim()
st = ch.split(/\s*,\s*/)
if (st.length === 0) j = indparf + 1
else {
nomvaleur = st[0]
pValeur = this.pointeur(NatCal.NTteValRPourComDyn, nomvaleur, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
if (st.length === 1) j = indparf + 1
else {
nomvaleur2 = st[1]
pValeur2 = this.pointeur(NatCal.NTteValRPourComDyn, nomvaleur2, indicecommentaire)
if (pValeur2 !== null) { // Ligne corrigée version 6.4. Faisait référence à pValeur
this.listValDynUsed.add(pValeur)
this.listValDynUsed.add(pValeur2)
}
j = indparf + 1
}
}
}
}
}
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\If{', j)) !== -1) && j < len) {
// On recherche la parenthèse fermante correspondante
indparf = chaineAAnalyser.indexOf('}', jdeb + 4)
if (indparf === -1) break
else {
// On crée une chaine formée de ce qu'il y a entre \if{ et la parenthèse fermante
ch = chaineAAnalyser.substring(jdeb + 4, indparf).trim()
pValeur = this.pointeur(NatCal.NTteValPourComDynSaufFonc, ch, indicecommentaire)
if (pValeur === null) j = indparf + 1
else {
this.listValDynUsed.add(pValeur)
j = indparf + 1
}
}
}
// Version 8.8 : Si on utilise des insertions de code LaTeX venant d'un autre affichage LaTeX
// via le code LaTeX spécial \Lat{tagLatex} il faut ajouter à la liste des dépendances celles du LaTeX dont on insère le contenu
j = 0
while (((jdeb = chaineAAnalyser.indexOf('\\Lat{', j)) !== -1) && j < len) {
indparf = chaineAAnalyser.indexOf('}', jdeb + 5)
if (indparf === -1) break
else {
ch = chaineAAnalyser.substring(jdeb + 5, indparf).trim()
const lat = this.listeProprietaire.getLaTeXByTagBefore(ch, indicecommentaire + (estDansListe ? 0 : 1))
if (lat !== null) {
// On a trouvé un code \Lat{ch} valide on rajoute les dépendances de l'affichage LaTeX lat
// à celles de this
// On ajoute le latex trouvé à la liste des valeurs utilisées bien que ce ne soit pas une valeur
// Ainsi si le LaTeX dont le code est inséré dépend d'une valeur dynamique this en dépendra aussi
this.listValDynUsed.add(lat)
}
j = indparf + 1
}
}
}
CLatex.prototype.positionne = function (infoRandom, dimf) {
let ch = this.chaineCommentaire
if (this.listValDynUsed.longueur() !== 0) {
ch = this.traiteCodesLatex(ch)
// Ligne suivante modifiée version 6.8.1 pour un meilleur fonctionnement des macros d'apparition d'objets
// Si c'est un affichage LaTeX qui était masqué et qu'une macro d'apparition a mis son membre
// masqué à false, il faut que l'affichage soit créé
// this.isToBeUpdated = (ch !== this.chaineLatex)
this.isToBeUpdated = (ch !== this.chaineLatex) || !this.hasgElement
this.chaineLatex = ch
} else {
this.chaineLatex = ch
// Ligne suivante modifiée version 6.8.1 pour un meilleur fonctionnement des macros d'apparition d'objets
// Si c'est un affichage LaTeX qui était masqué et qu'une macro d'apparition a mis son membre
// masqué à false, il faut que l'affichage soit créé
// this.isToBeUpdated = false
this.isToBeUpdated = !this.hasgElement
}
// CAffLiePt.prototype.positionne.call(this, infoRandom, dimf) // Modifié version 6.4.1
CAffLiePt.prototype.positionnePourIm.call(this, infoRandom, dimf)
}
/**
* Attention : Version 6.4.1 : Il faut redéfinir positionneFull pour CLaTeX car sinon c'est le positionneFull
* de CAffLiePt qyi sera appelé
* @param {boolean} infoRandom
* @param {Dimf} dimf
*/
CLatex.prototype.positionneFull = function (infoRandom, dimf) {
this.positionne(infoRandom, dimf)
if (this.existe) this.isToBeUpdated = true
}
/**
* Fonction préparant l'affichage par MathJax en créant un div provisoire
* @param {boolean} bMemeMasque Si true la préparation se fait même si l'affichage est caché
* (sert dans la boîte de dialogue de protocole)
* @returns {void}
*/
CLatex.prototype.setReady4MathJax = function (bMemeMasque) {
// Modifié version 5.0.4 pour tenir compte des objts dupliqués d'un CLaTeX
// qui est masqué
const memeMasque = arguments.length === 0 ? false : bMemeMasque
if (!this.masque || this.hasDuplicate || memeMasque) {
this.typeset()
}
}
CLatex.prototype.createg = function () {
let w, h, va, decHor, decVer, xdisp, ydisp
const g = cens('g')
try { // Modifié version mtgApp
const s = this.html.firstChild
const svg = s.cloneNode(true)
g.appendChild(svg)
w = parseFloat($(s).attr('width')) * this.ex
h = parseFloat($(s).attr('height')) * this.ex
va = parseFloat($(svg).css('vertical-align')) * this.ex
svg.setAttribute('width', w + 'px')
svg.setAttribute('height', h + 'px')
$(svg).css('vertical-align', va + 'px')
// s.setAttribute("width", w + "px");
// s.setAttribute("height", h + "px");
// Lignes suivantes supprimées version 6.4.0
// var t = Fonte.tailleLatex(this.taillePolice); // Modifié 5.0.2
// if (h < t) h = t;
switch (this.alignementHorizontal) {
case CAffLiePt.alignHorCent :
decHor = w / 2
break
case CAffLiePt.alignHorRight :
decHor = w
break
default : decHor = 0
}
xdisp = -decHor
this.rectAff.x = xdisp - 1
const decalageBas = 3 + h * 0.03
switch (this.alignementVertical) {
case CAffLiePt.alignVerCent :
decVer = h / 2
break
case CAffLiePt.alignVerLow :
decVer = h + decalageBas
break
default : decVer = -decalageBas
}
ydisp = -decVer
this.rectAff.y = ydisp - decalageBas + 1
this.rectAff.width = w + 2
this.rectAff.height = h + 2 * decalageBas
/*
var clone = s.cloneNode(true);
clone.setAttribute("x", (this.rectAff.x).toString()+"px");
clone.setAttribute("y", (this.rectAff.y).toString()+"px");
clone.setAttribute("width", w+"px");
clone.setAttribute("height",h+"px");
clone.setAttribute("style","");
*/
svg.setAttribute('x', (xdisp).toString() + 'px')
svg.setAttribute('y', (ydisp).toString() + 'px')
g.appendChild(svg)
if (this.effacementFond || (this.encadrement !== StyleEncadrement.Sans)) { this.creeRectangle(g, this.couleurFond) }
// this.deleteDiv(); // Plus utilisé version 6.4
// Ligne suivante modifiée version 6.5.2
// g.setAttribute('pointer-events', 'none')
g.setAttribute('pointer-events', this.pointerevents)
// Ajout version 5.0.1 pour compatibilité avec l'explorer qui ne clipe pas correctement
// Supprimé version mtgApp car pour des lieux d'objets de LaTeX liés à un point lié le point lié peut être hors-fenêtre
/*
if ((this.pointLie !== null) && !this.pointLie.dansFenetre)
g.setAttribute("visibility", "hidden");
else g.setAttribute("visibility", "visible");
*/
g.setAttribute('visibility', 'visible')
// Ajout version Version 6.0 //////////////////////////////////////////
this.positionneAngText(g)
/// //////////////////////////////////////////////////////////////////////
// Ajout version MtgApp pour pouvoir déplacer un CEditeurEquation
if (this.owner !== null) this.g = g
//
return g
} catch (e) {
// this.deleteDiv(); // PLus utilisé version 6.4 avec MathJax3
return g // Retourne un g vide en cas de problème
}
}
/**
* @returns {void}
*/
CLatex.prototype.setReady4MathJaxUpdate = function setReady4MathJaxUpdate () {
if (this.isToBeUpdated || (this.g && (this.g.childNodes.length === 0))) this.setReady4MathJax()
}
CLatex.prototype.update = function update (svg) {
const oldg = this.g
if (!this.isToBeUpdated) {
this.positionneAngText(this.g)
} else {
const g = this.createg()
svg.replaceChild(g, oldg)
g.setAttribute('id', this.id)
this.g = g
if (this.cbmap) this.resetEventListeners() // Ajout version 6.5.2
}
// Ajout version 5.0.1
if ((this.pointLie !== null) && !this.pointLie.dansFenetre) {
this.g.setAttribute('visibility', 'hidden')
} else {
this.g.setAttribute('visibility', 'visible')
}
}
CLatex.prototype.parametres = function (nbArg, ch, debut, fin) {
let i, j, codePar, indsuiv
indsuiv = -1
const len = ch.length
// On remplace les retours chariot par des espaces
// Non il ne faut pas remplacer les retours chariots par des espaces car pour le LaTeX cela revient
// à rajouter des espaces et pour les affichages de texte ce n'est pas anodin.
// ch = ch.replace(/\n/g, ' ')
let chtest = ch
// On remplace dans ch tous les \\left{ et \\right} pas des espaces car ce sont pas
// de vraies accolades en respectant le même nombre de caractères (8 pour \right\{ et 7 pour \left\{)
chtest = chtest.replace(/\\right\\}/g, ' '.repeat(8)).replace(/\\left\\{/g, ' '.repeat(7))
const chret = new Array(nbArg)
i = debut
for (j = 0; j < nbArg; j++) {
if (i >= len) return null
if (chtest.substring(i).trim().charAt(0) !== '{') {
return null
}
codePar = 1
const indparouvdeb = chtest.substring(i).indexOf('{')
i += indparouvdeb + 1
indsuiv = i
let deb = chtest.substring(i)
let indpar
while (((indpar = deb.search(/[{}]/g)) !== -1) && codePar > 0) {
const cardeb = deb.charAt(indpar)
if (cardeb === '{') {
codePar++
} else {
codePar--
if (codePar < 0) return null
}
deb = deb.substring(indpar + 1)
indsuiv += indpar + 1
}
if (codePar !== 0) return null
chret[j] = ch.substring(i, indsuiv - 1)
i = indsuiv
}
fin.setValue(indsuiv - 1)
return chret
}
/**
* Fonction traitant les codes LaTeX spécifiques à MathGraph32.
* Pour plus de renseignements sur ces codes spéciaux, voir l'aide en ligne dans MathGraph32 (appuyer sur F1).
* @param {string} ch La chaîne contenant les codes.
* @returns {string}
*/
CLatex.prototype.traiteCodesLatex = function (ch) {
let ideb, param, chremp
const fin = new Pointeur(0)
// Les codes \If peuvent être imbriqués les uns dans les autres. Il faut les rechecher tant
// qu'il y en a et les traiter depuis le début.
while ((ideb = ch.indexOf('\\If', 0)) !== -1) {
param = this.parametres(3, ch, ideb + 3, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('If')
break
} else {
chremp = this.traiteCodeIf(param)
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
}
// Ajout version 6.7. Traitement des codes \ValFrac. A faire impérativement avant les \Val
// Renvoie la fraction continue équivalente au résultat de l'argument à 10^(-12) près
while ((ideb = ch.indexOf('\\ValFrac', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 8, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('ValFrac')
break
}
chremp = this.traiteCodeValFrac(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Traitement des codes \Val
while ((ideb = ch.indexOf('\\Val', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 4, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('Val')
break
} else {
chremp = ''
try {
chremp = this.traiteCodeVal(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
} catch (e) {
ch = ch.substring(0, ideb) + codeErreur('Val')
}
}
}
// Ajout version 7.3 : Traitement des codes \Decomp et \DecompFull
const tab = ['\\DecompFull', '\\Decomp'] // Ordre important il faut commencer par le plus long
for (let k = 0; k < 2; k++) {
while ((ideb = ch.indexOf(tab[k], 0)) !== -1) {
param = this.parametres(1, ch, ideb + tab[k].length, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('Decomp')
break
} else {
chremp = ''
try {
chremp = this.traiteCodeDecomp(param[0], k === 0)
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
} catch (e) {
ch = ch.substring(0, ideb) + codeErreur('Decomp')
}
}
}
}
// Traitement des codes \FracRed
while ((ideb = ch.indexOf('\\FracRed', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 8, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('FracRed')
break
}
chremp = this.traiteCodeFracRed(param[0])
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Version 6.7 : Traitement des codes \ForSimpFrac. A faire impérativement avant les \For
// Fonctionne comme les \ForSimp sauf que les valeurs non entières sont remplacées par
// des fractions correspondant à la fraction continue équivalente à 10^(-12) près
while ((ideb = ch.indexOf('\\ForSimpFrac', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 12, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('ForSimpFrac')
break
}
chremp = this.traiteCodeForSimpFrac(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Traitement des codes \ForSimp. A faire impérativement avant les \For
while ((ideb = ch.indexOf('\\ForSimp', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 8, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('ForSimp')
break
}
chremp = this.traiteCodeForSimp(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Traitement des codes \ForRep. A faire impérativement avant les \For
while ((ideb = ch.indexOf('\\ForRep', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 7, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('ForRep')
break
}
chremp = this.traiteCodeForRep(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Traitement des codes \For
while ((ideb = ch.indexOf('\\For', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 4, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('For')
break
}
chremp = this.traiteCodeFor(param[0].trim())
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
ideb = fin.getValue() + 1
}
// Traitement des codes \CalcSimp. A faire impérativement avant les \Calc
while ((ideb = ch.indexOf('\\CalcSimp', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 9, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('CalcSimp')
break
}
chremp = this.traiteCodeCalcSimp(param[0])
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Traitement des codes \Calc
while ((ideb = ch.indexOf('\\Calc', 0)) !== -1) {
param = this.parametres(1, ch, ideb + 5, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('Calc')
break
}
chremp = this.traiteCodeCalc(param[0])
ch = ch.substring(0, ideb) + chremp + ch.substring(fin.getValue() + 1)
}
// Version 8.8 : On regarde s'il y a des codes \Lat pour insérer le code LaTeX
// d'un affichage défini avant le code LaTeX étant \Lat{tag} où tag est le tag
// de l'affichage LaTeX dont le code est à réutiliser
// Version 8.8 (n° de version 22) : traitement des codes \Lat{tag}
// qui remplacent par le code LaTeX renvoyé par l'affichage LaTeX de tag tag
// à condition que cet affichage LaTeX soit défini avant
const list = this.listeProprietaire
while ((ideb = ch.indexOf('\\Lat', 0)) !== -1) {
const param = this.parametres(1, ch, ideb + 4, fin)
if (param === null) {
ch = ch.substring(0, ideb) + codeErreur('Lat')
break
}
const indfin = fin.getValue()
const index = this.index
// Si this.index est égal à -1 c'est qu'on est en train de créer un nouveau LaTeX
// provisoire dans l'aperçu de la boîte de dialogue d'édition de LaTeX
const lat = list.getLaTeXByTagBefore(param[0], index === -1 ? list.longueur() : index)
if (lat === null) {
ch = ch.substring(0, ideb) + codeErreur('Lat') + ch.substring(indfin + 1)
} else {
const remp = lat.existe ? lat.chaineLatex : ''
ch = ch.substring(0, ideb) + ' ' + remp + ' ' + ch.substring(indfin + 1)
}
}
return ch
}
/**
* Fonction traitant les codes \Val permettant d'insérer la représentation décimale
* d'un calcul réel ou complexe ou d'une variable dans l'affichage.
* @param {string[]} param Tableau de chaînes contenant les codes.
* @returns {string} : La chaîne traitée.
*/
CLatex.prototype.traiteCodeVal = function (param) {
// On sépare cette chaine avec les virgules
let nomvaleur, indfin, pValeur, chnbdec, nbdecimales, chplus, signePlusImpose, nombre
let chnombre = ''
const st = param.split(/\s*,\s*/)
if (st.length !== 0) {
nomvaleur = st[0]
indfin = this.listValDynUsed.longueur() - 1
pValeur = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDynSaufFonc, nomvaleur, indfin)
if (pValeur !== null) {
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
if (pValeur.existe) {
if (pValeur.estMatrice()) {
if (st.length >= 2) chnbdec = st[1]
else chnbdec = '2'
nbdecimales = parseInt(chnbdec.trim())
chnombre = pValeur.latexMat(nbdecimales)
} else {
if (st.length >= 2) {
chnbdec = st[1]
if (chnbdec === '+') {
chnombre = pValeur.rendChaineValeurPourCommentaire(2)
if (chnombre.indexOf('-') === 0) chnombre = ' -' + chnombre.substring(1)
else chnombre = ' +' + chnombre
} else {
// On retire les espaces de début
chnbdec = chnbdec.trim()
nbdecimales = parseInt(chnbdec)
chnombre = pValeur.rendChaineValeurPourCommentaire(nbdecimales)
// Si le troisième paramètre :
// commence par + : on impose un signe + devant l'affichage si le nombre est positif ou nul
// finit par un zéro : on impose un signe + devant l'affichage si le nombre est positif ou nul
// et on n'affiche rien si le nombre est nul
// finit par 1 : on n'affiche pas le nombre si le nombre est égal à 1 et on affiche un signe - sil est égal à -1
if (st.length >= 3) {
chplus = st[2]
// On retire les éventuels espaces de début
chplus = chplus.trim()
signePlusImpose = chplus.indexOf('+') === 0
if (signePlusImpose) {
if (chnombre.indexOf('-') === -1) chnombre = '+' + chnombre
}
if (chplus.indexOf('0') === chplus.length - 1) {
nombre = pValeur.rendValeur()
if (nombre === 0) return ' '
} else {
nombre = pValeur.rendValeur()
if (chplus.indexOf('1') === chplus.length - 1) {
if (nombre === 1) return signePlusImpose ? '+' : ' '
else if (nombre === -1) return '-'
}
}
}
}
} else {
// Si le nombre de décimales n'est pas précisé, on en met deux par défaut
return pValeur.rendChaineValeurPourCommentaire(2)
}
}
}
}
} else return codeErreur('Val')
return chnombre
}
CLatex.prototype.traiteCodeValFrac = function (param) {
let chnombre = ''
const st = param.split(/\s*,\s*/)
if (st.length !== 0) {
const nomvaleur = st[0]
const indfin = this.listValDynUsed.longueur() - 1
const pValeur = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDynSaufFoncSaufComp, nomvaleur, indfin)
if (pValeur !== null) {
if (pValeur.existe) {
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
if (pValeur.estMatrice()) {
return pValeur.latexMatFrac()
} else {
const res = pValeur.rendValeur()
if (res === Math.floor(res)) chnombre = String(res)
else {
chnombre = codeLatexFracCont(fracCont(res))
}
if (st.length >= 2) {
let chplus = st[1]
// On retire les éventuels espaces de début
chplus = chplus.trim()
const signePlusImpose = chplus.indexOf('+') === 0
if (signePlusImpose) {
if (chnombre.indexOf('-') === 0) chnombre = ' -' + chnombre.substring(1)
else chnombre = ' +' + chnombre
}
if (chplus.indexOf('0') === chplus.length - 1) {
if (res === 0) return ' '
} else {
if (chplus.indexOf('1') === chplus.length - 1) {
if (res === 1) return signePlusImpose ? ' + ' : ' '
else if (res === -1) return ' - '
}
}
}
}
}
} else return codeErreur('ValFrac')
} else return codeErreur('ValFrac')
return chnombre
}
/**
* Fonction traitant les codes \Decomp et \DecompFull et qui fournit la décomposition en produit de facteurs premiers
* d'un entier au moins égal à 2
* @param{string} param Doit contenir la nom de la valeur réelle à décomposer
* @param {boolean} bfull Si true, on répète les facteurs au lieu de mettre des exposants
* @returns {string}
*/
CLatex.prototype.traiteCodeDecomp = function (param, bfull) {
let chnombre = ''
const st = param.split(/\s*,\s*/)
if (st.length !== 0) {
const nomvaleur = st[0]
const indfin = this.listValDynUsed.longueur() - 1
const pValeur = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValRPourComDyn, nomvaleur, indfin)
if (pValeur !== null) {
if (pValeur.existe) {
// Si la valeur n'existe pas, on ne l'inclut pas dans la chaîne à afficher
const res = pValeur.rendValeur()
if (!zero(res - Math.round(res)) || (res > 10000000)) return chaineNombre(res, 12)
const nb = Math.round(res)
const neg = nb < 0
const absnb = Math.abs(nb)
if (absnb === 1 || nb === 0) return String(nb)
const decomp = decompPrim(Math.round(absnb)) // Tableau dont le premier élélent est un tableau contenant les facteurs premiers
// et le second un tableau contenant les exposants
const factprem = decomp[0]
const expo = decomp[1]
const nbfactprem = factprem.length
if (bfull) {
let nbfact = 0
for (let i = 0; i < nbfactprem; i++) {
for (let k = 0; k < expo[i]; k++) {
nbfact++
if (nbfact !== 1) chnombre += '\\times'
chnombre += String(factprem[i])
}
}
} else {
for (let i = 0; i < nbfactprem; i++) {
if (i !== 0) chnombre += '\\times '
chnombre += String(factprem[i]) + '^{' + String(expo[i]) + '}'
}
}
if (neg) chnombre = '-' + chnombre
}
} else return codeErreur('Decomp')
} else return codeErreur('Decomp')
return chnombre
}
/**
* Fonction traitant les codes \FracRed permettant d'insérer une fraction
* qui est la fraction réduite représentant un quotient de deux entiers.
* @param {string[]} param Tableau de chaînes contenant les codes..
* @returns {string} : La chaîne traitée.
*/
CLatex.prototype.traiteCodeFracRed = function (param) {
let nomvaleur1, indfin, pValeurNum, num, nomvaleur2, pValeurDen, den, numabs, denabs, signePlusImpose, chsig, g, num1, den1, positif
// On sépare cette chaine avec les virgules
let res = ' '
const st = param.split(/\s*,\s*/)
if (st.length !== 0) {
nomvaleur1 = st[0]
// On recherche si c'est bien le nom d'une valeur valide
// Il ne faut pas que la valeur ait été définie après l'affichage de valeur
// Si c'est le nom d'une valeur utilisée, elle est comprise dans la
// liste listValDynUsed
indfin = this.listValDynUsed.longueur() - 1
pValeurNum = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValRPourComDyn, nomvaleur1, indfin)
if (pValeurNum === null) return codeErreur('FracRed')
if (pValeurNum.existe) {
num = pValeurNum.rendValeur(false)
if (st.length >= 2) {
nomvaleur2 = st[1]
pValeurDen = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValRPourComDyn, nomvaleur2, indfin)
if (pValeurDen === null) return codeErreur('FracRed')
if (pValeurDen.existe) {
den = pValeurDen.rendValeur()
if (den === 0) return codeErreur('FracRed')
numabs = Math.abs(num)
denabs = Math.abs(den)
if ((numabs !== Math.floor(numabs)) || (numabs > MAX_VALUE) ||
(denabs !== Math.floor(denabs)) || (denabs > MAX_VALUE) || (denabs === 0)) return codeErreur('FracRed')
else {
signePlusImpose = false
chsig = ''
if (st.length >= 3) {
chsig = st[2]
if (chsig.indexOf('+') === 0) signePlusImpose = true
}
if ((num === 0) && (chsig !== '') && (chsig.charAt(chsig.length - 1) === '0')) return ' '
g = pgcd(numabs, denabs)
num1 = numabs / g
den1 = denabs / g
positif = (num * den >= 0)
if (zero13(den1 - 1)) {
if (zero13(num1 - 1) && (chsig !== '') && (chsig.charAt(chsig.length - 1) === '1')) {
if (positif) return signePlusImpose ? ' + ' : ' '
else return ' - '
}
res = chaineNombre(num1, 0)
} else res = ' \\dfrac{' + chaineNombre(num1, 0) + '}{' + chaineNombre(den1, 0) + '} '
if (positif && signePlusImpose) res = ' +' + res
else { if (!positif) res = ' -' + res }
// Abandonné car on utilise des \dfrac partout : Modification version 6.4. On utilise displaystyle sinon trop petit avec MathJax3
// return '\\displaystyle ' + res
return res
}
}
}
}
}
return res
}
/**
* Fonction traitant les codes \If permettant d'avoir un affichage conditionnel
* La syntaxe est \If{Test}{Affichage si 1}{Affichage sinon}
* @param {string} param Tableau de chaînes contenant les codes.
* @returns {string} : La chaîne égale au résultat du test .
*/
CLatex.prototype.traiteCodeIf = function (param) {
let num
const indfin = this.listValDynUsed.longueur() - 1
// Modifié version 4.7.2
// CValDyn pValeurNum = latex.listValDynUsed.pointeurValeurOuFonction(nomvaleur,indfin);
const pValeurNum = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDynSaufFonc, param[0], indfin)
if (pValeurNum === null) return codeErreur('If')
if (pValeurNum.existe) {
if (pValeurNum.getNatureCalcul() === NatCal.NCalculComplexe) {
const z = new Complexe()
pValeurNum.rendValeurComplexe(z)
if ((z.x === 1) && (z.y === 0)) return param[1]; else return param[2]
} else {
if (pValeurNum.estDeNatureCalcul(NatCal.NTteValRPourComDyn)) {
num = pValeurNum.rendValeur()
if (num === 1) return param[1]; else return param[2]
} else return param[2]
}
} else return param[2]
}
/**
* Fonction traitant les codes \For permettant d'obtenir le codeLaTex d'un calcul ou une fonction.
* Les calculs ou variables utilisés dans la fonction ne sont pas remplacés par leur valeur.
* La syntaxe est \For{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne à traiter.
* @returns {string} : La chaîne contenant le code LaTeX.
*/
CLatex.prototype.traiteCodeFor = function (param) {
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(Nat.or(NatCal.NCalcouFoncParFormule, NatCal.NMatrice), param, indfin)
if (calcul !== null) {
if (calcul.className === 'CMatrice') {
const n = calcul.n
const p = calcul.p
let res = '\\begin{matrix}'
for (let i = 0; i < n; i++) {
if (i !== 0) res += '\\\\'
for (let j = 0; j < p; j++) {
if (j !== 0) res += ' & '
const val = calcul.tabVal[i][j]
res += val.calcul.chaineLatexSansPar(null)
}
}
return res + '\\end{matrix}'
} else {
const varFor = calcul.variableFormelle()
return calcul.calcul.chaineLatexSansPar(varFor)
}
} else return codeErreur('For')
}
/**
* Fonction traitant les codes \Calc permettant d'afficher la formule d'un calcul ou une fonction
* Cette formule est rénvoyée telle qu'elle serait écrite (avec les signes * de multiplication).
* Le code renvoyé n'est pas un code LaTeX.
* Les calculs ou variables utilisés dans la formule ne sont pas remplacés par leur valeur.
* La syntaxe est \Calc{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne contenant les codes.
* @returns {string} : La chaîne contenant la formule.
*/
CLatex.prototype.traiteCodeCalc = function (param) {
let varFor, nbv, k, chret, stb, i
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDyn, param, indfin)
if (calcul !== null) {
varFor = null
if (calcul.estDeNatureCalcul(Nat.or(NatCal.NFonction, NatCal.NFonctionComplexe))) {
varFor = new Array(1)
varFor[0] = calcul.nomsVariables
} else {
if (calcul.estDeNatureCalcul(Nat.or(NatCal.NFoncPlusieursVar, NatCal.NFoncCPlusieursVar))) {
nbv = calcul.nbVar
varFor = new Array(nbv)
for (k = 0; k < nbv; k++) varFor[k] = calcul.nomsVariables[k]
}
}
// chret = "\\text{" + calcul.calcul.chaineCalculSansPar(varFor) + "}"; //.Modifié version 4.9.2.3
chret = calcul.calcul.chaineCalculSansPar(varFor)
// Il faut remplacer les caractères ^ par \^{}
stb = chret
for (i = 0; i < stb.length; i++) {
if (stb.charAt(i) === '^') {
// stb.replace(i, i+1, "\\;\\^{}\\;");
// stb = stb.substring(0, i-1) + "\\;\\^{}\\;" + stb.substring(i+1); //.Modifié version 4.9.2.3
stb = stb.substring(0, i) + ' \\;\\widehat{\\;\\;}\\; ' + stb.substring(i + 1)
i = i + 8
}
}
return stb.toString()
} else return codeErreur('Calc')
}
/**
* Fonction traitant les codes \Calc permettant d'afficher la formule d'un calcul ou une fonction
* Cette formule est rénvoyée telle qu'elle serait écrite (avec les signes * de multiplication).
* Le code renvoyé n'est pas un code LaTeX.
* Les calculs ou variables utilisés dans la formule sont remplacés par leur valeur.
* L'expression du calcul est simplifiée le plus possible (par exemple les termes nuls d'une somme
* ne sont pas écrits, 1*x est remplacé par x).
* La syntaxe est \Calc{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne contenant les codes.
* @returns {string} : La chaîne contenant la formule.
*/
CLatex.prototype.traiteCodeCalcSimp = function (param) {
let varFor, chret, stb, i
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDyn, param.toString(), indfin)
if (calcul !== null) {
varFor = calcul.variableFormelle()
chret = '\\text{' + calcul.calcul.calculAvecValeursRemplacees(false)
.calculNormalise(true, false, false).chaineCalculSansPar(varFor) + '}'
// Il faut remplacer les caractères ^ par \^{}
stb = chret
for (i = 0; i < stb.length; i++) {
if (stb.charAt(i) === '^') {
stb = stb.substring(0, i - 1) + '\\;\\^{}\\;' + stb.substring(i + 1)
i = i + 8
}
}
return stb.toString()
} else return codeErreur('CalcSimp')
}
/**
* Fonction traitant les codes \ForSimp permettant d'obtenir le codeLaTex d'un calcul ou une fonction.
* Les calculs ou variables utilisés dans la fonction sont remplacés par leur valeur décimale.
* L'expression du calcul est simplifiée le plus possible (par exemple les termes nuls d'une somme
* ne sont pas écrits, 1*x est remplacé par x).
* La syntaxe est \ForSimp{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne à traiter.
* @returns {string} : La chaîne contenant le code LaTeX.
*/
CLatex.prototype.traiteCodeForSimp = function (param) {
let varFor
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(Nat.or(NatCal.NCalcouFoncParFormule, NatCal.NMatrice), param, indfin)
if (calcul !== null) {
if (calcul.className === 'CMatrice') {
const n = calcul.n
const p = calcul.p
let res = '\\begin{matrix}'
for (let i = 0; i < n; i++) {
if (i !== 0) res += '\\\\'
for (let j = 0; j < p; j++) {
if (j !== 0) res += ' & '
const val = calcul.tabVal[i][j]
res += val.calcul.calculAvecValeursRemplacees(false).calculNormalise(true, false, false).chaineLatexSansPar(null)
}
}
return res + '\\end{matrix}'
}
varFor = calcul.variableFormelle()
// return calcul.calcul.calculAvecValeursRemplacees().calculNormalise(true, false, false).chaineLatexSansPar(varFor);
// Abandonné car on utilise des \dfrac partout : Modification version 6.4 pour que le résultat avec MathJax3 soit équivalent à celui de l'ancienne version de MathJax
// return '\\displaystyle ' + calcul.calcul.calculAvecValeursRemplacees(false).calculNormalise(true, false, false).chaineLatexSansPar(varFor)
return calcul.calcul.calculAvecValeursRemplacees(false).calculNormalise(true, false, false).chaineLatexSansPar(varFor)
} else return codeErreur('ForSimp')
}
/**
* Fonction traitant les codes \ForRep permettant d'obtenir le codeLaTex d'un calcul ou une fonction.
* Les calculs ou variables utilisés dans la fonction sont remplacés par leur valeur décimale.
* Contrairement au code \ForSimp les multiplications ou divisions par 1, -1 et les sommes avec 0
* ne sont pas simplifiées
* La syntaxe est \ForRep{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne à traiter.
* @returns {string} : La chaîne contenant le code LaTeX.
*/
CLatex.prototype.traiteCodeForRep = function (param) {
let varFor
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(Nat.or(NatCal.NCalcouFoncParFormule, NatCal.NMatrice), param, indfin)
if (calcul !== null) {
if (calcul.className === 'CMatrice') {
const n = calcul.n
const p = calcul.p
let res = '\\begin{matrix}'
for (let i = 0; i < n; i++) {
if (i !== 0) res += '\\\\'
for (let j = 0; j < p; j++) {
if (j !== 0) res += ' & '
const val = calcul.tabVal[i][j]
res += val.calcul.calculAvecValeursRemplacees(false).chaineLatexSansPar(null)
}
}
return res + '\\end{matrix}'
}
varFor = calcul.variableFormelle()
// return calcul.calcul.calculAvecValeursRemplacees().calculNormalise(true, false, false).chaineLatexSansPar(varFor);
// Abandonné car on utilise des \dfrac partout : Modification version 6.4 pour que le résultat avec MathJax3 soit équivalent à celui de l'ancienne version de MathJax
// return '\\displaystyle ' + calcul.calcul.calculAvecValeursRemplacees(false).calculNormalise(true, false, false).chaineLatexSansPar(varFor)
return calcul.calcul.calculAvecValeursRemplacees(false).chaineLatexSansPar(varFor)
} else return codeErreur('ForSimp')
}
/**
* Fonction traitant les codes \For permettant d'obtenir le codeLaTex d'un calcul ou une fonction.
* Les calculs ou variables utilisés dans la fonction sont remplacés par leur valeur s'ils
* prennent une valeur entière et par une fraction continue équivalente à 10^(-12) sinon.
* L'expression du calcul est simplifiée le plus possible (par exemple les termes nuls d'une somme
* ne sont pas écrits, 1*x est remplacé par x).
* La syntaxe est \For{a} où a est le nom d'une calcul ou d'une fonction.
* @param {string} param La chaîne à traiter.
* @returns {string} : La chaîne contenant le code LaTeX.
*/
CLatex.prototype.traiteCodeForSimpFrac = function (param) {
let varFor
const indfin = this.listValDynUsed.longueur() - 1
const calcul = this.listValDynUsed.pointeurParNatureCalcul(NatCal.NTteValPourComDyn, param, indfin)
if (calcul !== null) {
if (calcul.estMatrice()) {
if (calcul.className === 'CMatrice') {
const n = calcul.n
const p = calcul.p
let res = '\\begin{matrix}'
for (let i = 0; i < n; i++) {
if (i !== 0) res += '\\\\'
for (let j = 0; j < p; j++) {
if (j !== 0) res += ' & '
const val = calcul.tabVal[i][j]
// Ici calculAvecValeursRemplacees remplace les valeurs par leur fraction continue approchée à 10^(-12) près
res += val.calcul.calculAvecValeursRemplacees(true).calculNormalise(true, false, true).chaineLatexSansPar(null)
}
}
return res + '\\end{matrix}'
} else return codeErreur('ForSimp')
}
varFor = calcul.variableFormelle()
// return calcul.calcul.calculAvecValeursRemplacees().calculNormalise(true, false, false).chaineLatexSansPar(varFor);
// Abandonné car on utilise des \dfrac partout : Modification version 6.4 pour que le résultat avec MathJax3 soit équivalent à celui de l'ancienne version de MathJax
// return '\\displaystyle ' + calcul.calcul.calculAvecValeursRemplacees(true).calculNormalise(true, false, false).chaineLatexSansPar(varFor)
return calcul.calcul.calculAvecValeursRemplacees(true).calculNormalise(true, false, true).chaineLatexSansPar(varFor)
} else return codeErreur('ForSimp')
}
/*
CLatex.prototype.read = function(inps, list){
CCommentaire.prototype.read.call(this, inps, list);
};
*/
/**
* Fonction remplaçant dans this.commentairre les appels dynamiques de calcul,
* fonction ou variable nommé ancienNom par nouveauNom.
* @param {string} ancienNom
* @param {string} nouveauNom
* @returns {boolean} : la chaîne traitée.
*/
CLatex.prototype.remplaceNomValeurDynamique = function (ancienNom, nouveauNom) {
// On supprime d'abord tous les caractères espace suivant un { ou une virgule ou précédant une accolade
let buffer = this.chaineCommentaire
const chaineInitiale = buffer
// Ajout version 6.7 : Traitement des codes \ValFrac
let ch1 = '\\\\ValFrac{[ ]*' + ancienNom + '[ ]*\\}'
let ch2 = '\\ValFrac{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\Val\\{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\Val{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
// Ajout version 7.3 pour le nouveau code \DecompFull
ch1 = '\\\\DecompFull\\{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\DecompFull{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
// Ajout version 7.3 pour le nouveau code \Decomp
ch1 = '\\\\Decomp\\{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\Decomp{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\Val{[ ]*' + ancienNom + '[ ]*,'
ch2 = '\\Val{' + nouveauNom + ','
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\For{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\For{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
// Version 6.7 : traitement des nouveaux codes \SimpFor
ch1 = '\\\\ForSimpFrac{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\ForSimpFrac{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\ForSimp{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\ForSimp{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\ForRep{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\ForRep{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\Calc{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\Calc{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\CalcSimp{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\CalcSimp{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\FracRed{[ ]*' + ancienNom + '[ ]*,'
ch2 = '\\FracRed{' + nouveauNom + ','
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
ch1 = '\\\\If{[ ]*' + ancienNom + '[ ]*\\}'
ch2 = '\\If{' + nouveauNom + '}'
buffer = buffer.replace(new RegExp(ch1, 'g'), ch2)
this.chaineCommentaire = buffer
this.remplaceNomValeurDynamiqueApresVirgule('\\FracRed{', ancienNom, nouveauNom)
return (chaineInitiale !== this.chaineCommentaire)
}
/**
* Fonction recherchant dans les codes spéciaux utilisant une virgue ancienNom et le replaçant par nouveauNom.
* @param {string} code contient \FracRed qui est pour le moment le seul code avec virgules
* dont le deuxième argument peut être le nom d'un calcul ou une variable.
* @param {string} ancienNom Le nom de calcul, variable ou fonction à remplacer.
* @param {string} nouveauNom Le nom du calcul, variable ou fonction qui remplace.
* @returns {void}
*/
CLatex.prototype.remplaceNomValeurDynamiqueApresVirgule = function (code, ancienNom, nouveauNom) {
let ind = 0
while ((ind = this.chaineCommentaire.indexOf(code, ind)) !== -1) {
// On recherche la première accolade fermante
const indacf = this.chaineCommentaire.indexOf('}', ind + code.length)
if (indacf !== -1) {
const left = this.chaineCommentaire.substring(0, ind + code.length - 1)
const right = this.chaineCommentaire.substring(indacf + 1)
let mid = this.chaineCommentaire.substring(ind + code.length - 1, indacf + 1)
let ch1 = ',' + ancienNom + ' '
let ch2 = ',' + nouveauNom + ' '
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
ch1 = ',' + ancienNom + ','
ch2 = ',' + nouveauNom + ','
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
ch1 = ' ' + ancienNom + ','
ch2 = ' ' + nouveauNom + ','
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
ch1 = ' ' + ancienNom + ' '
ch2 = ' ' + nouveauNom + ' '
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
ch1 = ' ' + ancienNom + '}'
ch2 = ' ' + nouveauNom + '}'
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
ch1 = ',' + ancienNom + '}'
ch2 = ',' + nouveauNom + '}'
mid = mid.replace(new RegExp(ch1, 'g'), ch2)
this.chaineCommentaire = left + mid + right
}
ind = ind + code.length - 1
}
}
CLatex.prototype.chaineDesignation = function () {
return 'desLatex'
}
// Fonction rajoutée version 6.7.2 pour que quand on lit une lsite d'objets la liste soit au courant
// si elle nécessite d'utiliser MathJax ou non
CLatex.prototype.read = function (inps, list) {
this.listeProprietaire.useLatex = true
CCommentaire.prototype.read.call(this, inps, list)
}