exercices/6e/6G14.js

import Exercice from '../Exercice.js'
import { mathalea2d, vide2d } from '../../modules/2dGeneralites.js'
import { context } from '../../modules/context.js'
import { listeQuestionsToContenu, randint, range, egal, rangeMinMax, shuffle, combinaisonListes, contraindreValeur, choice } from '../../modules/outils.js'
import { point, pointIntersectionDD, droite, droiteParPointEtParallele, droiteParPointEtPerpendiculaire, droiteParPointEtPente, rotation, codageAngleDroit, latexParCoordonneesBox, pointSurDroite, segment, pointIntersectionCC } from '../../modules/2d.js'
export const amcReady = true
export const amcType = 'AMCOpen' // type de question AMC
export const titre = 'Utiliser les propriétés des droites perpendiculaires'

/**
 * Ref 6G14
 * @author Jean-Claude Lhote (EE : pour l'ajout d'AMC et la possibilité de sélectionner différents mélanges)
 * @author Mickael Guironnet (refactoring avec ajout des 4 à 6 et des figures)
 * publié le 22/11/2020
 */
export const uuid = '6a336'
export const ref = '6G14'
export default function ProprietesParallelesPerpendiculaires () {
  'use strict'
  Exercice.call(this)
  this.titre = titre
  this.nbQuestions = 3
  this.nbCols = 1
  this.nbColsCorr = 1
  this.sup = 4
  this.sup2 = false
  this.sup3 = true
  this.correctionDetailleeDisponible = true
  this.correctionDetaillee = false
  this.nouvelleVersion = function () {
    this.autoCorrection = []
    let typesDeQuestionsDisponibles = []
    let questionsParNiveau = []
    if (!this.sup2) {
      questionsParNiveau.push(range(3))
      questionsParNiveau.push(rangeMinMax(4, 6))
      questionsParNiveau.push(rangeMinMax(9, 15))
      questionsParNiveau.push(rangeMinMax(19, 31, 20))
      questionsParNiveau.push(questionsParNiveau[0].concat(questionsParNiveau[1].concat(questionsParNiveau[2]).concat(questionsParNiveau[3])))
    } else {
      questionsParNiveau = [[2], [15], [31], [2, 15, 31]]
    }
    let AvecMelange = true
    if (!this.sup) { // Si aucun melange n'est saisi
      typesDeQuestionsDisponibles = questionsParNiveau[4]
    } else {
      if (typeof (this.sup) === 'number') { // Si c'est un nombre, on duplique ce nombre et on insère un - entre les deux.
        this.sup = this.sup + '-' + this.sup
      } else { AvecMelange = false }

      let QuestionsDisponibles = []
      const IndiceNew = [0, 0, 0, 0, 0]
      let NumQuestionsDisponibles
      QuestionsDisponibles = this.sup.split('-')// Sinon on créé un tableau à partir des valeurs séparées par des -
      for (let i = 0; i < this.nbQuestions; i++) { // on a un tableau avec des strings : ['1', '1', '2']
        NumQuestionsDisponibles = contraindreValeur(1, 5, parseInt(QuestionsDisponibles[i % QuestionsDisponibles.length]), 4) - 1
        typesDeQuestionsDisponibles[i] = choice(questionsParNiveau[NumQuestionsDisponibles], typesDeQuestionsDisponibles.slice(IndiceNew[NumQuestionsDisponibles])) // Ce slice permet de gérer, par exemple, le mélange 1-1-2 pour 10 questions car il n'y a pas assez de choix différents pour le mélange 1.
        if (typesDeQuestionsDisponibles[i] === undefined) { // Dans le cas, on a épuisé tous les choix différents d'un mélange
          IndiceNew[NumQuestionsDisponibles] = i
          typesDeQuestionsDisponibles[i] = choice(questionsParNiveau[NumQuestionsDisponibles], typesDeQuestionsDisponibles.slice(IndiceNew[NumQuestionsDisponibles]))
        }
      }
    }
    let listeTypeDeQuestions = []
    if (AvecMelange) {
      listeTypeDeQuestions = combinaisonListes(
        typesDeQuestionsDisponibles,
        this.nbQuestions
      )
    } else { listeTypeDeQuestions = typesDeQuestionsDisponibles }

    this.listeQuestions = [] // Liste de questions
    this.listeCorrections = [] // Liste de questions corrigées
    const droiteColor = (context.isHtml ? ['red', 'blue', 'green', 'black', 'magenta', '#f15929'] : ['black', 'black', 'black', 'black', 'black', 'black'])

    for (let i = 0, texte, texteCorr, cpt = 0; i < this.nbQuestions && cpt < 50;) {
      texte = ''
      texteCorr = ''

      const numDroites = shuffle([1, 2, 3, 4, 5])
      // const numDroites = [1, 2, 3, 4, 5]
      const d = []; const dE = []; const P = []; const objets = []; const objets2 = []
      let code = []; let code2 = []

      switch (listeTypeDeQuestions[i]) {
        // \n1 : Une étape (de 0 à 3)\n2 : Une étape avec distracteur (de 4 à 6)\n3 : Deux étapes (de 9 à 15)\n4 : Trois étapes (de 19 à 31)\n5 : Mélange']
        case 0: // si 1//2 et 2//3 alors 1//3
          code = [[1, 2, 1], [2, 3, 1]]
          break
        case 1: // si 1//2 et 2T3 alors 1T3
          code = [[1, 2, 1], [2, 3, -1]]
          break
        case 2: // si 1T2 et 2T3 alors 1//3
          code = [[1, 2, -1], [2, 3, -1]]
          break
        case 3: // si 1T2 et 2//3 alors 1T3
          code = [[1, 2, -1], [2, 3, 1]]
          break
        case 4: // si 1T2 et 2//3 alors 1T3 et 4 distracteur
          code = [[1, 2, -1], [2, 3, 1]]
          code2 = [[1, 4, 1]]
          break
        case 5: // si 1T2 et 2T3 alors 1//3 et 4 distracteur
          code = [[1, 2, -1], [2, 3, -1]]
          code2 = [[2, 4, 1]]
          break
        case 6: // si 1//2 et 2//3 alors 1//3 et 4 distracteur
          code = [[1, 2, 1], [2, 3, 1]]
          code2 = [[1, 4, -1]]
          break
        case 8: // Si 1//2 et 2//3 et 3//4 alors 1//4
          code = [[1, 2, 1], [2, 3, 1], [3, 4, 1]]
          break
        case 9: // Si 1//2 et 2//3 et 3T4 alors 1T4
          code = [[1, 2, 1], [2, 3, 1], [3, 4, -1]]
          break
        case 10: // Si 1//2 et 2T3 et 3//4 alors 1T4
          code = [[1, 2, 1], [2, 3, 1], [3, 4, 1]]
          break
        case 11: // Si 1//2 et 2T3 et 3T4 alors 1//4
          code = [[1, 2, 1], [2, 3, -1], [3, 4, -1]]
          break
        case 12: // Si 1T2 et 2//3 et 3//4 alors 1T4
          code = [[1, 2, -1], [2, 3, 1], [3, 4, 1]]
          break
        case 13: // Si 1T2 et 2//3 et 3T4 alors 1//4
          code = [[1, 2, -1], [2, 3, 1], [3, 4, -1]]
          break
        case 14: // Si 1T2 et 2T3 et 3//4 alors 1//4
          code = [[1, 2, -1], [2, 3, -1], [3, 4, 1]]
          break
        case 15: // Si 1T2 et 2T3 et 3T4 alors 1T4
          code = [[1, 2, -1], [2, 3, -1], [3, 4, -1]]
          break
        case 16: // Si 1//2 et 2//3 et 3//4 et 4//5 alors 1//5
          code = [[1, 2, 1], [2, 3, 1], [3, 4, 1], [4, 5, 1]]
          break
        case 17: // Si 1//2 et 2//3 et 3T4 et 4//5 alors 1T5
          code = [[1, 2, 1], [2, 3, 1], [3, 4, -1], [4, 5, 1]]
          break
        case 18: // Si 1//2 et 2T3 et 3//4 et 4//5 alors 1T5
          code = [[1, 2, 1], [2, 3, -1], [3, 4, 1], [4, 5, 1]]
          break
        case 19: // Si 1//2 et 2T3 et 3T4 et 4//5 alors 1//5
          code = [[1, 2, 1], [2, 3, -1], [3, 4, -1], [4, 5, 1]]
          break
        case 20: // Si 1T2 et 2//3 et 3//4 et 4//5 alors 1T5
          code = [[1, 2, -1], [2, 3, 1], [3, 4, 1], [4, 5, 1]]
          break
        case 21: // Si 1T2 et 2//3 et 3T4 et 4//5 alors 1//5
          code = [[1, 2, -1], [2, 3, 1], [3, 4, -1], [4, 5, 1]]
          break
        case 22: // Si 1T2 et 2T3 et 3//4 et 4//5 alors 1//5
          code = [[1, 2, -1], [2, 3, -1], [3, 4, 1], [4, 5, 1]]
          break
        case 23: // Si 1T2 et 2T3 et 3T4 et 4//5 alors 1T5
          code = [[1, 2, -1], [2, 3, -1], [3, 4, -1], [4, 5, 1]]
          break
        case 24: // Si 1//2 et 2//3 et 3//4 et 4T5 alors 1T5
          code = [[1, 2, 1], [2, 3, 1], [3, 4, 1], [4, 5, -1]]
          break
        case 25: // Si 1//2 et 2//3 et 3T4 et 4T5 alors 1//5
          code = [[1, 2, 1], [2, 3, 1], [3, 4, -1], [4, 5, -1]]
          break
        case 26: // Si 1//2 et 2T3 et 3//4 et 4T5 alors 1//5
          code = [[1, 2, 1], [2, 3, -1], [3, 4, 1], [4, 5, -1]]
          break
        case 27: // Si 1//2 et 2T3 et 3T4 et 4T5 alors 1T5
          code = [[1, 2, 1], [2, 3, -1], [3, 4, -1], [4, 5, -1]]
          break
        case 28: // Si 1T2 et 2//3 et 3//4 et 4T5 alors 1//5
          code = [[1, 2, -1], [2, 3, 1], [3, 4, 1], [4, 5, -1]]
          break
        case 29: // Si 1T2 et 2//3 et 3T4 et 4T5 alors 1T5
          code = [[1, 2, -1], [2, 3, 1], [3, 4, -1], [4, 5, -1]]
          break
        case 30: // Si 1T2 et 2T3 et 3//4 et 4T5 alors 1T5
          code = [[1, 2, -1], [2, 3, -1], [3, 4, 1], [4, 5, -1]]
          break
        case 31: // Si 1T2 et 2T3 et 3T4 et 4T5 alors 1//5
          code = [[1, 2, -1], [2, 3, -1], [3, 4, -1], [4, 5, -1]]
          break
      }

      // enoncé mélangé
      const couleurd = []
      const phrases = []
      texte += 'On sait que '
      couleurd.push(randint(0, 5))
      const codeAll = code.concat(code2)
      for (let j = 0; j < codeAll.length; j++) {
        let textetemp = `$(d_${numDroites[codeAll[j][0] - 1]})`
        if (codeAll[j][2] === 1) {
          textetemp += '//'
          couleurd.push(couleurd[j])
        } else {
          textetemp += '\\perp'
          couleurd.push((couleurd[j] + 1) % 6)
        }
        textetemp += `(d_${numDroites[codeAll[j][1] - 1]})$`
        phrases.push(textetemp)
      }
      // phrases=shuffle(phrases)
      for (let j = 0; j < codeAll.length - 1; j++) {
        texte += phrases[j]
        if (j !== codeAll.length - 2) texte += ', '
        else texte += ' et '
      }
      texte += phrases[codeAll.length - 1] + '.<br>'

      // construction de la figure
      context.fenetreMathalea2d = [-2, -2, 15, 10] // important avec la création des droites
      const labels = []
      P.push(point(0, 0))
      let droiteP = droiteParPointEtPente(P[0], randint(-1, 1, -2) / 10, '', droiteColor[couleurd[0]])
      droiteP.epaisseur = 2
      droite.pointilles = false
      d.push(droiteP)
      const droiteE = droite(point(droiteP.x1, droiteP.y1), point(droiteP.x2, droiteP.y2), '')
      droiteE.epaisseur = 2
      dE.push(droiteE)
      labels.push(labelOnLine(droiteE, `$(d_${numDroites[codeAll[0][0] - 1]})$`))
      objets.push(d[0])
      objets2.push(dE[0])
      for (let x = 0; x < codeAll.length; x++) {
        if (codeAll[x][2] === 1) {
          P.push(point((x + 1) * 2, (x + 1) * 2))
          droiteP = droiteParPointEtParallele(P[x + 1], d[codeAll[x][0] - 1], '', droiteColor[couleurd[x + 1]])
          droiteP.epaisseur = 2
          droiteP.pointilles = d[[codeAll[x][0] - 1]].pointilles
          d.push(droiteP)
          const droiteP2 = droite(point(droiteP.x1, droiteP.y1), point(droiteP.x2, droiteP.y2), '')
          droiteP2.epaisseur = 2
          dE.push(droiteP2)
          labels.push(labelOnLine(droiteP2, `$(d_${numDroites[codeAll[x][1] - 1]})$`))
        } else {
          P.push(point((x + 1) * 2, (x + 1) * 2))
          droiteP = droiteParPointEtPerpendiculaire(P[x + 1], d[codeAll[x][0] - 1], '', droiteColor[couleurd[x + 1]])
          droiteP.epaisseur = 2
          droiteP.pointilles = x % 3 + 1
          d.push(droiteP)
          const droiteP2 = droite(point(droiteP.x1, droiteP.y1), point(droiteP.x2, droiteP.y2), '')
          labels.push(labelOnLine(droiteP2, `$(d_${numDroites[codeAll[x][1] - 1]})$`))
          droiteP2.epaisseur = 2
          dE.push(droiteP2)
          const Inter = pointIntersectionDD(d[codeAll[x][0] - 1], droiteP)
          const PP = rotation(P[x + 1], Inter, 90)
          objets.push(codageAngleDroit(PP, Inter, P[x + 1], 'black', 0.6))
          objets2.push(codageAngleDroit(PP, Inter, P[x + 1], 'black', 0.6))
        }
        objets.push(d[x + 1])
        objets2.push(dE[x + 1])
      }
      objets2.push(...labels)
      objets.push(...labels)

      if (this.sup3) {
        texte += (context.vue === 'diap' ? '<center>' : '') + mathalea2d({ xmin: -2, xmax: 15, ymin: -2, ymax: 10, pixelsParCm: 20, scale: (context.vue !== 'latex' ? 0.3 : 0.6), mainlevee: false, amplitude: 0.3 }, objets2) + '<br>' + (context.vue === 'diap' ? '</center>' : '')
      }
      texte += `Que peut-on dire de $(d_${numDroites[code[0][0] - 1]})$ et $(d_${numDroites[code[code.length - 1][1] - 1]})$ ?`
      if (context.isAmc && !this.sup3) {
        texte += ' On pourra s\'aider en traçant une figure.'
      }

      // correction raisonnement ordonné
      texteCorr = 'À partir de l\'énoncé, on peut réaliser le schéma suivant (il en existe une infinité).<br>'
      if ([2, 5, 15, 31].indexOf(listeTypeDeQuestions[i]) === -1 && !this.sup2) {
        texteCorr += ' Les droites données parallèles dans l\'énoncé sont de même '
        texteCorr += (context.html) ? ' couleur/style.<br>' : 'style.<br>'
      }
      texteCorr += mathalea2d({ xmin: -2, xmax: 15, ymin: -2, ymax: 10, pixelsParCm: 20, scale: (context.vue !== 'latex' ? 0.3 : 0.6), mainlevee: false, amplitude: 0.3 }, objets) + '<br>'
      for (let j = 0; j < code.length - 1; j++) {
        if (this.correctionDetaillee) texteCorr += 'On sait que : '
        else texteCorr += 'Comme '
        texteCorr += `$(d_${numDroites[code[j][0] - 1]})`
        if (code[j][2] === 1) texteCorr += '//'
        else texteCorr += '\\perp'
        texteCorr += `(d_${numDroites[code[j][1] - 1]})$ et `
        texteCorr += `$(d_${numDroites[code[j + 1][0] - 1]})`
        if (code[j + 1][2] === 1) texteCorr += '//'
        else texteCorr += '\\perp'
        texteCorr += `(d_${numDroites[code[j + 1][1] - 1]})$`
        // quelle propriété ?
        if (code[j][2] * code[j + 1][2] === -1) { // Une parallèle et une perpendiculaire
          if (this.correctionDetaillee) texteCorr += '.<br> Or «Si deux droites sont parallèles alors toute droite perpendiculaire à l\'une est aussi perpendiculaire à l\'autre».<br>Donc'
          else texteCorr += ', on en déduit que '
          texteCorr += ` $(d_${numDroites[code[0][0] - 1]})\\perp(d_${numDroites[code[j + 1][1] - 1]})$.<br>`
          code[j + 1][0] = code[j][0]
          code[j + 1][2] = -1
        } else if (code[j][2] > 0) { // deux parallèles
          if (this.correctionDetaillee) texteCorr += '.<br> Or «Si deux droites sont parallèles à une même droite alors elles sont parallèles entre elles».<br>Donc'
          else texteCorr += ', on en déduit que '
          texteCorr += ` $(d_${numDroites[code[0][0] - 1]})//(d_${numDroites[code[j + 1][1] - 1]})$.<br>`
          code[j + 1][0] = code[j][0]
          code[j + 1][2] = 1
        } else { // deux perpendiculaires
          if (this.correctionDetaillee) texteCorr += '.<br> Or «Si deux droites sont perpendiculaires à une même droite alors elles sont parallèles entre elles».<br>Donc'
          else texteCorr += ', on en déduit que '
          texteCorr += ` $(d_${numDroites[code[0][0] - 1]})//(d_${numDroites[code[j + 1][1] - 1]})$.<br>`
          code[j + 1][0] = code[j][0]
          code[j + 1][2] = 1
        }
      }

      /** ********************** AMC Open *****************************/
      this.autoCorrection[i] = {}
      this.autoCorrection[i].options = { ordered: false }
      this.autoCorrection[i].enonce = texte + '<br>'
      this.autoCorrection[i].propositions = [
        {
          texte: texteCorr,
          statut: 3
        }
      ]
      /****************************************************/

      if (this.listeQuestions.indexOf(texte) === -1) {
        // Si la question n'a jamais été posée, on en crée une autre
        this.listeQuestions.push(texte + '<br>')
        this.listeCorrections.push(texteCorr + '<br>')
        i++
      }
      cpt++
    }

    listeQuestionsToContenu(this)
  }
  this.besoinFormulaireTexte = ['Nombre d\'étapes de raisonnement', 'Nombres séparés par des tirets\n1 : Une étape\n2 : Une étape avec distracteur\n3 : Deux étapes\n4 : Trois étapes\n5 : Mélange']
  this.besoinFormulaire2CaseACocher = ['Que des perpendiculaires', false]
  this.besoinFormulaire3CaseACocher = ['Avec le dessin', true]
}
/**
 * Ajouter une étiquette sur une droite.
 * @param {*} droite La droite où on va rajouter une étiquette
 * @param {*} nom Le nom de la droite doit être au format latex, c'est-à-dire compris entre $ et $
 * @param {*} options Les options permettant de personnaliser la position de l'étiquette et la mise en forme
 *  options.preferedPosition La position à privilégier si possible sur le bord de l'image ('left', 'right', 'above', 'below')
 *  options.usedPosition Un tableau des anciennes positions déjà allouées pour éviter les colisions avec des étiquettes d'autres droites
 *  options.taille La taille de la police de l'étiquette par défaut 6
 *  options.color La couleur de l'étiquette par défaut 'red'
 * @returns LatexParCoordonneesBox L'étiquette
 *
 * Exemple :
 *   context.fenetreMathalea2d = [xmin + 0.2, ymin, xmax, ymax] // important pour la position des labels
 *   const d3nom = labelOnLine(d3, '$' + noms[3] + '$', { color: 'blue', taille: 8, preferedPosition: 'left' })
 *   const d0nom = labelOnLine(d0, '$' + noms[0] + '$', { color: 'red', taille: 8, usedPosition: [d3nom] })
 *
 * @author Mickael Guironnet
 */
export function labelOnLine (droite, nom, options = {}) {
  if (options.preferedPosition === undefined) options.preferedPosition = 'auto'
  if (options.usedPosition === undefined) options.usedPosition = []
  if (options.taille === undefined) options.taille = 6
  if (options.color === undefined) options.color = 'red'

  let debug = false

  // const largeur = Math.ceil((nom.replaceAll('$', '').length) * 10 * Math.log10(options.taille))
  const largeur = Math.ceil((nom.replaceAll('$', '').length) * options.taille * 10 / 12)
  const hauteur = 20
  let absNom, ordNom, leNom, anchor, usedPosition; const positions = []
  if (nom !== '') {
    if (egal(droite.b, 0, 0.05)) { // ax+c=0 x=-c/a est l'équation de la droite
      // droite quasi verticale
      absNom = -droite.c / droite.a + largeur * 0.5 / context.pixelsParCm + 2 / context.pixelsParCm
      ordNom = context.fenetreMathalea2d[1] + 1 // l'ordonnée du label est ymin +1
      anchor = 'right'
      usedPosition = 'below'
      leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
      positions.push({ label: leNom, position: usedPosition, anch: anchor })
    } else if (egal(droite.a, 0, 0.05)) { // by+c=0 y=-c/b est l'équation de la droite
      // droite quasi horizontale
      absNom = context.fenetreMathalea2d[0] + 1 // l'abscisse du label est xmin +1
      ordNom = -droite.c / droite.b + hauteur * 0.5 / context.pixelsParCm
      anchor = 'above'
      usedPosition = 'left'
      leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
      positions.push({ label: leNom, position: usedPosition, anch: anchor })
    } else { // a et b sont différents de 0 ax+by+c=0 est l'équation
      // y=(-a.x-c)/b est l'equation cartésienne et x=(-by-c)/a
      const y0 = (-droite.a * (context.fenetreMathalea2d[0] + 1) - droite.c) / droite.b
      const y1 = (-droite.a * (context.fenetreMathalea2d[2] - 1) - droite.c) / droite.b
      const x0 = (-droite.b * (context.fenetreMathalea2d[1] + 1) - droite.c) / droite.a
      const x1 = (-droite.b * (context.fenetreMathalea2d[3] - 1) - droite.c) / droite.a
      if (y0 > context.fenetreMathalea2d[1] && y0 < context.fenetreMathalea2d[3]) {
        // à gauche : soit en dessous ou en dessous
        absNom = context.fenetreMathalea2d[0] + 1
        ordNom = y0 - droite.pente * (largeur * 0.5 / context.pixelsParCm) + (droite.pente > 0 ? -1 : 1) * hauteur * 0.5 / context.pixelsParCm
        anchor = (droite.pente > 0 ? 'below' : 'above')
        usedPosition = 'left'
        if (ordNom < context.fenetreMathalea2d[1] + 1 || ordNom > context.fenetreMathalea2d[3] - 1) {
          if (debug) console.log('probl:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[1] + 1) + '<' + ordNom + '<' + (context.fenetreMathalea2d[3] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
        // à gauche : soit en dessous ou en dessous
        absNom = context.fenetreMathalea2d[0] + 1
        ordNom = y0 + droite.pente * (largeur * 0.5 / context.pixelsParCm) - (droite.pente > 0 ? -1 : 1) * hauteur * 0.5 / context.pixelsParCm
        anchor = (droite.pente > 0 ? 'above' : 'below')
        usedPosition = 'left'
        if (ordNom < context.fenetreMathalea2d[1] + 1 || ordNom > context.fenetreMathalea2d[3] - 1) {
          if (debug) console.log('probl:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[1] + 1) + '<' + ordNom + '<' + (context.fenetreMathalea2d[3] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
      }
      if (y1 > context.fenetreMathalea2d[1] && y1 < context.fenetreMathalea2d[3]) {
        // à droite
        absNom = context.fenetreMathalea2d[2] - 1
        ordNom = y1 - droite.pente * (largeur * 0.5 / context.pixelsParCm) + (droite.pente > 0 ? -1 : 1) * hauteur * 0.5 / context.pixelsParCm
        anchor = (droite.pente > 0 ? 'below' : 'above')
        usedPosition = 'right'
        if (ordNom < context.fenetreMathalea2d[1] + 1 || ordNom > context.fenetreMathalea2d[3] - 1) {
          if (debug) console.log('probl:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[1] + 1) + '<' + ordNom + '<' + (context.fenetreMathalea2d[3] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
      }
      if (x0 > context.fenetreMathalea2d[0] && x0 < context.fenetreMathalea2d[2]) {
        // en bas : soit à gauche ou à droite
        absNom = x0 + (droite.pente > 0 ? -1 : 1) * largeur * 0.5 / context.pixelsParCm - (droite.pente > 0 ? 1 : 1) * (hauteur * 0.5 / context.pixelsParCm) / droite.pente - (droite.pente > 0 ? 1 : -1) * 2 / context.pixelsParCm
        ordNom = context.fenetreMathalea2d[1] + 1
        anchor = (droite.pente > 0 ? 'left' : 'right')
        usedPosition = 'below'
        if (absNom < context.fenetreMathalea2d[0] + 1 || absNom > context.fenetreMathalea2d[2] - 1) {
          if (debug) console.log('problème:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[0] + 1) + '<' + absNom + '<' + (context.fenetreMathalea2d[2] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
        // en bas de l'autre côté
        absNom = x0 - (droite.pente > 0 ? -1 : 1) * largeur * 0.5 / context.pixelsParCm + (droite.pente > 0 ? 1 : 1) * (hauteur * 0.5 / context.pixelsParCm) / droite.pente + (droite.pente > 0 ? 1 : -1) * 2 / context.pixelsParCm
        ordNom = context.fenetreMathalea2d[1] + 1
        anchor = (droite.pente > 0 ? 'right' : 'left')
        usedPosition = 'below'
        if (absNom < context.fenetreMathalea2d[0] + 1 || absNom > context.fenetreMathalea2d[2] - 1) {
          if (debug) console.log('problème:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[0] + 1) + '<' + absNom + '<' + (context.fenetreMathalea2d[2] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
      }
      if (x1 > context.fenetreMathalea2d[0] && x1 < context.fenetreMathalea2d[2]) {
        // au haut : soit à gauche ou à droite
        absNom = x1 + (droite.pente > 0 ? -1 : 1) * largeur * 0.5 / context.pixelsParCm - (droite.pente > 0 ? 1 : 1) * (hauteur * 0.5 / context.pixelsParCm) / droite.pente - (droite.pente > 0 ? 1 : -1) * 2 / context.pixelsParCm
        ordNom = context.fenetreMathalea2d[3] - 1
        anchor = (droite.pente > 0 ? 'left' : 'right')
        usedPosition = 'above'
        if (absNom < context.fenetreMathalea2d[0] + 1 || absNom > context.fenetreMathalea2d[2] - 1) {
          if (debug) console.log('problème:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[0] + 1) + '<' + absNom + '<' + (context.fenetreMathalea2d[2] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
        // au haut de l'autre côté
        absNom = x1 - (droite.pente > 0 ? -1 : 1) * largeur * 0.5 / context.pixelsParCm + (droite.pente > 0 ? 1 : 1) * (hauteur * 0.5 / context.pixelsParCm) / droite.pente + (droite.pente > 0 ? 1 : -1) * 2 / context.pixelsParCm
        ordNom = context.fenetreMathalea2d[3] - 1
        anchor = (droite.pente > 0 ? 'right' : 'left')
        usedPosition = 'above'
        if (absNom < context.fenetreMathalea2d[0] + 1 || absNom > context.fenetreMathalea2d[2] - 1) {
          if (debug) console.log('problème:nom:' + nom + ':position:' + usedPosition + (context.fenetreMathalea2d[0] + 1) + '<' + absNom + '<' + (context.fenetreMathalea2d[2] - 1))
        } else {
          leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
          positions.push({ label: leNom, position: usedPosition, anch: anchor })
        }
      }
      let xgauche, xdroite
      if (y0 > context.fenetreMathalea2d[1] && y0 < context.fenetreMathalea2d[3]) {
        xgauche = context.fenetreMathalea2d[0]
      } else {
        xgauche = Math.min(x0, x1)
      }
      if (y1 > context.fenetreMathalea2d[1] && y1 < context.fenetreMathalea2d[3]) {
        xdroite = context.fenetreMathalea2d[2]
      } else {
        xdroite = Math.max(x0, x1)
      }
      // au milieu
      absNom = (xgauche + xdroite) / 2
      ordNom = pointSurDroite(droite, absNom).y
      anchor = (droite.pente > 0 ? 'left' : 'right')
      usedPosition = 'middle'
      leNom = latexParCoordonneesBox(nom.substr(1, nom.length - 2), absNom, ordNom, options.color, largeur, hauteur, '', options.taille, { anchor })
      positions.push({ label: leNom, position: usedPosition, anch: anchor })
    }

    // vérifie s'il y a des colisions entre labels
    for (let i = 0; i < positions.length; i++) {
      if (positions[i].position === 'middle') continue
      const coli = []
      for (let j = 0; j < options.usedPosition.length; j++) {
        const label = options.usedPosition[j]
        const dis = segment(point(label.x, label.y), point(positions[i].label.x, positions[i].label.y)).longueur * context.pixelsParCm
        // colision deux rectangles
        const XYlabel = [label.x * context.pixelsParCm - label.largeur / 2, label.x * context.pixelsParCm + label.largeur / 2, label.y * context.pixelsParCm - label.hauteur / 2, label.y * context.pixelsParCm + label.hauteur / 2]
        const XYlabel2 = [positions[i].label.x * context.pixelsParCm - positions[i].label.largeur / 2, positions[i].label.x * context.pixelsParCm + positions[i].label.largeur / 2, positions[i].label.y * context.pixelsParCm - positions[i].label.hauteur / 2, positions[i].label.y * context.pixelsParCm + positions[i].label.hauteur / 2]
        if (debug) console.log('coli:nom:' + nom + ':position:' + positions[i].position + ':i:' + i + ':j:' + j + ':dis:' + dis.toFixed(2) + ':texte:' + label.texte + ':XYlabel:' + XYlabel[0].toFixed(1) + ',' + XYlabel[1].toFixed(1) + ',' + XYlabel[2].toFixed(1) + ',' + XYlabel[3].toFixed(1) + ':XYlabel2:' + XYlabel2[0].toFixed(1) + ',' + XYlabel2[1].toFixed(1) + ',' + XYlabel2[2].toFixed(1) + ',' + XYlabel2[3].toFixed(1))
        const colision = (XYlabel[0] < XYlabel2[1]) && (XYlabel[1] > XYlabel2[0]) && (XYlabel[2] < XYlabel2[3]) && (XYlabel[3] > XYlabel2[2])
        // colision deux cercles
        const r0 = Math.max(label.largeur / 2, label.hauteur / 2)
        const r1 = Math.max(positions[i].label.largeur / 2, positions[i].label.hauteur / 2)
        let colision2 = true
        if (dis > r0 + r1 || dis < Math.abs(r0 - r1)) colision2 = false
        coli[j] = [dis, colision]
        if (debug) console.log('coli:nom:' + nom + ':position:' + positions[i].position + ':anchor:' + positions[i].anch + ':i:' + i + ':j:' + j + ':dis:' + dis.toFixed(2) + 'texte:' + label.texte + ':colision:' + (colision ? '1' : '0') + ':coli_cer:' + (colision2?'1':'0'))
      }
      positions[i].colision = coli
    }
    // 1ere stratégie : la préférence de l'utilisateur
    // on vérifie seulement s'il y a une colision
    const found = [false, 0]
    for (let i = 0; i < positions.length && !found[0]; i++) {
      if (positions[i].position === 'middle') continue
      if (positions[i].position === options.preferedPosition) {
        found[0] = true
        for (let j = 0; j < options.usedPosition.length; j++) {
          if (positions[i].colision[j][1]) found[0] = false
          if (debug) console.log('1er:nom:' + nom + ':position:' + positions[i].position + ':i:' + i + ':j:' + j + ':colision:' + positions[i].colision[j][1] + ':preferedPosition:' + options.preferedPosition)
        }
        found[1] = i
      }
    }

    // 2e stratégie : le plus loin en terme de distance!
    let disMax = [0, 0, 0]
    for (let i = 0; i < positions.length && !found[0] && options.usedPosition.length > 0; i++) {
      if (positions[i].position === 'middle') continue
      let dis = [1000, 0, 0]
      for (let j = 0; j < options.usedPosition.length; j++) {
        if (positions[i].colision[j][0] < dis[0]) {
          dis = [positions[i].colision[j][0], i, j]
          if (debug) console.log('2e:nom:' + nom + ':position:' + positions[i].position + ':anchor:' + positions[i].anch + ':i:' + i + ':j:' + j + 'dis:' + dis[0].toFixed(2) + ':colision:' + positions[i].colision[j][1])
        }
      }
      if (dis[0] > disMax[0]) {
        disMax = dis
        if (debug) console.log('Max 2e:nom:' + nom + ':position:' + positions[i].position + ':anchor:' + positions[i].anch + ':i:' + i + 'dis:' + dis[0].toFixed(2))
      }
    }
    let colision = false
    if (disMax[0] > 0) {
      colision = positions[disMax[1]].colision[disMax[2]][1]
      if (debug) console.log('Max fin : 2e:nom:' + nom + ':position:' + positions[disMax[1]].position + ':anchor:' + positions[disMax[1]].anch + ':i:' + disMax[1] + ':j:' + disMax[2] + 'disMax:' + disMax[0] + ':colision:' + positions[disMax[1]].colision[disMax[2]][1])
    }
    // 1er : si préférence alors Ok sinon distance la plus loin sans chevauchement sinon la première solution si pas de comparaison sinon la dernière milieu
    leNom = found[0] ? positions[found[1]].label : (disMax[0] > 0 && !colision ? positions[disMax[1]].label : positions[options.usedPosition.length === 0 ? 0 : positions.length - 1].label)
  } else {
    leNom = vide2d()
  }
  return leNom
}