legacy/outils/3D/3D.js

import $ from 'jquery'
import { j3pAjouteBouton, j3pBoule, j3pDetruit, j3pDiv, j3pElement } from 'src/legacy/core/functions'
import { j3pCreeSegment, j3pCreeSVG, j3pCreeTexte, j3pCreeVecteur, j3pPolygone } from 'src/legacy/core/functionsSvg'

/** @module legacy/outils/3D/3D */

/*
window.objet = {
                sommets:[[],[1,-1,-1],[1,1,-1],[-1,1,-1],[-1,-1,-1],[1,-1,1],[1,1,1],[-1,1,1],[-1,-1,1]],
                faces:[[4,3,2,1],[1,2,6,5],[2,3,7,6],[3,4,8,7],[4,1,5,8],[5,6,7,8]],
                nomsommets:["","A","B","C","D","E","F","G","H"],
                objets : [
                    {nom:"O",type:"point",coord:[0,0,0]}
                ]
*/
function _3D (idconteneur, objet) {
  this.idconteneur = idconteneur

  if (objet.dim === undefined) {
    this.dim = { larg: 300, haut: 300 }
  } else {
    this.dim = objet.dim
    this.dim.larg = (objet.dim.larg) ? objet.dim.larg : 300
    this.dim.haut = objet.dim.haut ? objet.dim.haut : 300
  }

  // Alex :
  this.faces_cachees = objet.faces_cachees
  this.sommets = objet.sommets
  this.faces = objet.faces
  if (objet.repere === undefined) objet.repere = [1, 2, 4, 5]

  this.repere = objet.repere
  this.nomsommets = []
  // si nomsommets undefined les sommets sont nommés automatiquement "somk" (mais étiquettes non affichées)
  if (objet.nomsommets) {
    this.nomsommets.push('')
    for (let k = 1; k < this.sommets.length; k++) {
      this.nomsommets.push((objet.nomsommets[k] === '') ? 'som' + k : objet.nomsommets[k])
    }
  } else {
    this.nomsommets = ['']
    for (let k = 1; k < this.sommets.length; k++) this.nomsommets.push('som' + k)
  }
  this.sommetsvisibles = []
  if (objet.sommetsvisibles) {
    for (let k = 1; k < this.sommets.length; k++) this.sommetsvisibles[k] = objet.sommetsvisibles[k]
  } else {
    for (let k = 1; k < this.sommets.length; k++) this.sommetsvisibles[k] = false
  }

  if (objet.mef) {
    if ((objet.mef.couleursommets === undefined) && (objet.mef.couleurfaces === undefined)) {
      this.mef = { couleursommets: { defaut: 'F00' }, couleurfaces: { defaut: '#895632' } }
    } else if ((objet.mef.couleursommets) && (objet.mef.couleurfaces === undefined)) {
      this.mef = { couleursommets: objet.mef.couleursommets, couleurfaces: { defaut: '#895632' } }
    } else if ((objet.mef.couleursommets === undefined) && (objet.mef.couleurfaces)) {
      this.mef = { couleursommets: { defaut: 'F00' }, couleurfaces: objet.mef.couleursommets }
    } else {
      this.mef = objet.mef
    }
    this.mef.typerotation = (objet.mef.typerotation) ? objet.mef.typerotation : 'Oz'
  } else {
    this.mef = { typerotation: 'Oz', couleursommets: { defaut: 'F00' }, couleurfaces: { defaut: '#92BBD8' } }
  }

  this.objets = (objet.objets) ? objet.objets : []

  // remplissage du tableau objets avec les points sommets du solide
  const tab = []
  for (let k = 1; k < this.sommets.length; k++) {
    const o = {}
    o.estsommet = true// non construit en tant que point car déjà construit
    o.nom = this.nomsommets[k]
    o.type = 'point'
    o.coord = this.sommets[k]
    tab.push(o)
  }
  for (let k = 0; k < this.objets.length; k++) {
    if (this.objets[k].visible === undefined) this.objets[k].visible = true
    tab.push(this.objets[k])
  }
  this.objets = tab

  let d
  let sup = 0

  for (let k = 1; k < this.sommets.length; k++) {
    d = this.sommets[k][0] * this.sommets[k][0] + this.sommets[k][1] * this.sommets[k][1] + this.sommets[k][2] * this.sommets[k][2]
    if (d > sup) {
      sup = d
    }
  }

  this.zoom = (this.dim.zoom) ? this.dim.zoom : (Math.max(this.dim.larg / 3, this.dim.haut / 3)) / Math.sqrt(sup)
  // environ 50 dans le cas du cube
  const conteneur = j3pElement(this.idconteneur)
  this.rotation = { Ox: 0, Oy: 0, Oz: 0 }
  this.arotation = { Ox: 0, Oy: 0, Oz: 0 }
  this.rotation.type = this.mef.typerotation
  this.centreX = this.dim.larg / 2
  this.centreY = this.dim.haut / 2
  this.SVGfaces = []
  this.sommets2D = []

  this.construit()

  this.mode = 'rien' // "rotation"
  const that = this
  conteneur.tabIndex = '1'

  $('#' + this.conteneur).keypress(function (event) {
    if (event.keyCode !== 38 && event.keyCode !== 40) return
    switch (event.keyCode) {
      case 38:
        that.zoom -= 0.5
        break
      case 40:
        that.zoom += 0.5
        break
    }
    that.construit()
  })

  conteneur.addEventListener('mousemove',
    function (evt) {
      if (that.mode === 'rien') return

      const { left, top } = this.getBoundingClientRect()
      const courantX = event.clientX - left
      const courantY = event.clientY - top

      if (that.rotation.type === 'Oz') {
        that.rotation.Oz = that.arotation.Oz + Math.ceil((courantX - that.ancienX))
      } else {
        that.rotation.Ox = that.arotation.Ox + Math.ceil((courantX - that.ancienX))
      }
      that.rotation.Oy = that.arotation.Oy + Math.ceil((courantY - that.ancienY))
      that.construit()
      that.ancienX = courantX
      that.ancienY = courantY
      that.arotation.Ox = that.rotation.Ox
      that.arotation.Oy = that.rotation.Oy
      that.arotation.Oz = that.rotation.Oz
    }
  )

  conteneur.addEventListener('mousedown',
    function (evt) {
      that.mode = 'rotation'

      const { left, top } = this.getBoundingClientRect()
      that.ancienX = event.clientX - left
      that.ancienY = event.clientY - top
    }
  )

  conteneur.addEventListener('mouseup',
    function (evt) {
      that.mode = 'rien'
    }
  )

  j3pDiv(idconteneur, { id: this.idconteneur + 'divboutonbascule', contenu: '', coord: [0, 310] })
  j3pAjouteBouton(this.idconteneur + 'divboutonbascule', this.idconteneur + 'boutonbascule', 'MepBoutonsDG', 'Rotation ' + this.rotation.type)
  j3pElement(this.idconteneur + 'boutonbascule').addEventListener('click',
    function (evt) {
      if (evt.target.value === 'Rotation (Oz)') {
        evt.target.value = 'Rotation (Ox)'
        that.rotation.type = 'Ox'
      } else if (evt.target.value === 'Rotation (Oy)') {
        evt.target.value = 'Rotation (Oz)'
        that.rotation.type = 'Oz'
      } else {
        evt.target.value = 'Rotation (Oy)'
        that.rotation.type = 'Oy'
      }
    }
  )
}

_3D.prototype.anime = function (rotX, rotY, rotZ, lenteur) {
  // lenteur = 0 ==> instantané
  if (Number(lenteur) === 0) {
    this.rotation.Ox = rotX
    this.rotation.Oy = rotY
    this.rotation.Oz = rotZ
    this.construit()
    return
  }

  const nbmvt = 50
  const tabX = []
  const tabY = []
  const tabZ = []

  tabX[0] = this.rotation.Ox
  tabY[0] = this.rotation.Oy
  tabZ[0] = this.rotation.Oz
  for (let k = 1; k <= nbmvt; k++) {
    tabX[k] = tabX[0] + k * (rotX - tabX[0]) / nbmvt
    tabY[k] = tabY[0] + k * (rotY - tabY[0]) / nbmvt
    tabZ[k] = tabZ[0] + k * (rotZ - tabZ[0]) / nbmvt
  }

  this.objetanimation = { boucle: false, nbiter: nbmvt, itercourante: 1, tabX, tabY, tabZ }
  const that = this

  const loopTimerId = setInterval(function () {
    that.rotation.Ox = tabX[that.objetanimation.itercourante]
    that.rotation.Oy = tabY[that.objetanimation.itercourante]
    that.rotation.Oz = tabZ[that.objetanimation.itercourante]
    that.construit(that.rotation.Ox, that.rotation.Oy, that.rotation.Oz)
    that.objetanimation.itercourante++
    if (that.objetanimation.itercourante > that.objetanimation.nbiter) {
      clearInterval(loopTimerId)
    }
  }, lenteur)
}

// tab : coord 3D
// retourne les coord de tab dans le repere designe par this.repere
_3D.prototype.coordDansRepere = function (tab) {
  const O = this.objets[this.repere[0] - 1].coord
  const I = this.objets[this.repere[1] - 1].coord
  const J = this.objets[this.repere[2] - 1].coord
  const K = this.objets[this.repere[3] - 1].coord

  const passage = [
    [this.repere2[0][0], this.repere2[1][0], this.repere2[2][0]],
    [this.repere2[0][1], this.repere2[1][1], this.repere2[2][1]],
    [this.repere2[0][2], this.repere2[1][2], this.repere2[2][2]]
  ]

  let vecOI = [I[0] - O[0], I[1] - O[1], I[2] - O[2]]
  let vecOJ = [J[0] - O[0], J[1] - O[1], J[2] - O[2]]
  let vecOK = [K[0] - O[0], K[1] - O[1], K[2] - O[2]]
  let vecOM = [tab[0] - O[0], tab[1] - O[1], tab[2] - O[2]]

  vecOI = j3pProduitMatVec(passage, vecOI)
  vecOJ = j3pProduitMatVec(passage, vecOJ)
  vecOK = j3pProduitMatVec(passage, vecOK)
  vecOM = j3pProduitMatVec(passage, vecOM)

  const m = [[vecOI[0], vecOJ[0], vecOK[0]], [vecOI[1], vecOJ[1], vecOK[1]], [vecOI[2], vecOJ[2], vecOK[2]]]

  const m1 = j3pInverseMatrice(m)

  return j3pProduitMatVec(m1, vecOM)
}

_3D.prototype.estDansParallelepipedeRepere = function (tab) {
  const res = this.coordDansRepere(tab)
  // console.log(res)
  // console.log((res[0] < 1 + 0.05 && res[0] > -0.05) && (res[1] < 1 + 0.05 && res[1] > -0.05) && (res[2] < 1 + 0.05 && res[2] > -0.05))
  return ((res[0] < 1 + 0.05 && res[0] > -0.05) && (res[1] < 1 + 0.05 && res[1] > -0.05) && (res[2] < 1 + 0.05 && res[2] > -0.05))
}

_3D.prototype.to2D = function (tab) {
  // car vision suivant Oi
  return [tab[1] * this.zoom + this.centreX, -tab[2] * this.zoom + this.centreY]
}

// En degrés
_3D.prototype.rotationVecteur = function (vec, Ox, Oy, Oz) {
  let tempo1 = j3pRotation('Ox', Ox, vec)
  tempo1 = j3pRotation('Oy', Oy, tempo1)
  tempo1 = j3pRotation('Oz', Oz, tempo1)
  return tempo1
}

_3D.prototype.construit = function () {
  if (this.svg) j3pDetruit(this.idconteneur + 'figure')

  this.svg = j3pCreeSVG(this.idconteneur, {
    id: this.idconteneur + 'figure',
    width: this.dim.larg,
    height: this.dim.haut
  })
  const newsommets = []

  this.repere2 = [
    this.rotationVecteur([1, 0, 0], this.rotation.Ox, this.rotation.Oy, this.rotation.Oz),
    this.rotationVecteur([0, 1, 0], this.rotation.Ox, this.rotation.Oy, this.rotation.Oz),
    this.rotationVecteur([0, 0, 1], this.rotation.Ox, this.rotation.Oy, this.rotation.Oz)
  ]

  const passage = [
    [this.repere2[0][0], this.repere2[1][0], this.repere2[2][0]],
    [this.repere2[0][1], this.repere2[1][1], this.repere2[2][1]],
    [this.repere2[0][2], this.repere2[1][2], this.repere2[2][2]]
  ]

  // Les coordonnées des points sont relatives à repere2
  // Pour l’affichage, il faut déterminer les coordonnées des points dans le repere [1,0,0];[0,1,0];[0,0,1]

  for (let k = 0; k < this.sommets.length; k++) {
    newsommets.push(j3pProduitMatVec(passage, this.sommets[k]))
  }

  for (let k = 0; k < this.faces.length; k++) {
    const f = this.faces[k]
    const s = newsommets
    const vec1 = [s[f[1]][0] - s[f[0]][0], s[f[1]][1] - s[f[0]][1], s[f[1]][2] - s[f[0]][2]]
    const vec2 = [s[f[2]][0] - s[f[1]][0], s[f[2]][1] - s[f[1]][1], s[f[2]][2] - s[f[1]][2]]
    // console.log(vec1,vec2)
    // composante Ox du vecteur normal à la face
    // Si négative alors face cachée@
    const pv = j3pVectoriel(vec1, vec2)[0]

    for (let u = 0; u < f.length; u++) {
      const v = (u === f.length - 1) ? 0 : u + 1
      if (pv <= 0 && this.faces_cachees !== false) {
        j3pCreeSegment(this.svg, {
          id: this.idconteneur + 'face' + k + '_' + u,
          x1: this.to2D(s[f[u]])[0],
          y1: this.to2D(s[f[u]])[1],
          x2: this.to2D(s[f[v]])[0],
          y2: this.to2D(s[f[v]])[1],
          couleur: '#222222',
          epaisseur: 2,
          opacite: 1,
          pointilles: '2,6'
        })
      } else {
        j3pCreeSegment(this.svg, {
          id: this.idconteneur + 'face' + k + '_' + u,
          x1: this.to2D(s[f[u]])[0],
          y1: this.to2D(s[f[u]])[1],
          x2: this.to2D(s[f[v]])[0],
          y2: this.to2D(s[f[v]])[1],
          couleur: '#000000',
          epaisseur: 3,
          opacite: 1
        })
      }
    }

    if (pv > 0 || !this.faces_cachees) {
      const opacite = 0.5
      let tab = []
      if (f.length === 4) tab = [this.to2D(s[f[0]]), this.to2D(s[f[1]]), this.to2D(s[f[2]]), this.to2D(s[f[3]])]
      if (f.length === 3) tab = [this.to2D(s[f[0]]), this.to2D(s[f[1]]), this.to2D(s[f[2]])]

      const couleurface = (this.mef.couleurfaces['f' + k]) ? this.mef.couleurfaces['f' + k] : this.mef.couleurfaces.defaut
      j3pPolygone(this.svg, {
        id: this.idconteneur + 'face' + k,
        tab,
        couleur: couleurface,
        couleurRemplissage: couleurface,
        opaciteRemplissage: opacite
      })
    }
  }

  for (let k = 1; k < this.nomsommets.length; k++) {
    const nom = this.nomsommets[k]
    this.objets[this.numeroObjet(nom)].coord = this.sommets[k]

    if ((nom !== 'som' + k) && this.sommetsvisibles[k]) {
      const coord = j3pProduitMatVec(passage, this.sommets[k])

      const coord2D = this.to2D(coord)
      const couleursommet = (this.mef.couleursommets[nom]) ? this.mef.couleursommets[nom] : this.mef.couleursommets.defaut

      j3pCreeTexte(this.svg, {
        id: 'nomsommet' + nom,
        texte: nom,
        x: coord2D[0],
        y: coord2D[1] - 2,
        couleur: couleursommet,
        italique: true,
        taille: 12
      })
    }
  }

  // Construction des objets particuliers
  /*
   objets : [
                  {nom:"O",type:"point",coord:[0,0,0]},
                  {nom:"s1",type:"segment",ext1:"O",ext2:"K"}
              ]
  */

  for (let k = 0; k < this.objets.length; k++) {
    const o = this.objets[k]
    const nom = this.objets[k].nom
    if (o.type !== 'point') {
      if (this.objets[k].pointilles === undefined) this.objets[k].pointilles = false
      if (this.objets[k].couleur === undefined) this.objets[k].couleur = '#333'
    }
    switch (o.type) {
      case 'point':
        if (o.estsommet === undefined) {
          if (o.couleur === undefined) o.couleur = 'rouge'
          const couleur = o.couleur
          let couleurtexte = ''
          switch (o.couleur) {
            case 'rouge':
              couleurtexte = '#CC0000'
              break
            case 'bleu':
              couleurtexte = '#0000CC'
              break
            case 'vert':
              couleurtexte = '#008800'
              break
          }

          const tempo = j3pProduitMatVec(passage, o.coord)

          const coord2D = this.to2D(tempo)
          if (this.objets[k].visible) {
            j3pBoule(this.svg, {
              couleur,
              id: this.idconteneur + 'point' + o.nom,
              cx: coord2D[0],
              cy: coord2D[1],
              diametre: 10
            })
            j3pCreeTexte(this.svg, {
              id: this.idconteneur + 'textepoint' + o.nom + nom,
              texte: o.nom,
              x: coord2D[0] + 6,
              y: coord2D[1] - 5,
              couleur: couleurtexte,
              italique: true,
              taille: 12
            })
          }
          this.objets[k].coord2 = tempo
        } else {
          this.objets[k].coord2 = j3pProduitMatVec(passage, o.coord)
        }
        break

      case 'segment':
        // console.log('this.objets[this.numeroObjet(o.ext1)].coord2='+this.objets[this.numeroObjet(o.ext1)].coord2)
        {
          const coordext1 = this.objets[this.numeroObjet(o.ext1)].coord2
          const coordext2 = this.objets[this.numeroObjet(o.ext2)].coord2
          const coord2D1 = this.to2D(coordext1)
          const coord2D2 = this.to2D(coordext2)

          if (this.objets[k].visible) {
            if (this.objets[k].pointilles) {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1,
                pointilles: '6,6'
              })
            } else {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1
              })
            }
          }
        }
        break

      case 'droite':
        {
          const coordext1 = this.objets[this.numeroObjet(o.ext1)].coord2
          const coordext2 = this.objets[this.numeroObjet(o.ext2)].coord2
          const t = 100
          const debutDroite = [coordext1[0] - t * (coordext2[0] - coordext1[0]), coordext1[1] - t * (coordext2[1] - coordext1[1]), coordext1[2] - t * (coordext2[2] - coordext1[2])]
          const finDroite = [coordext1[0] + t * (coordext2[0] - coordext1[0]), coordext1[1] + t * (coordext2[1] - coordext1[1]), coordext1[2] + t * (coordext2[2] - coordext1[2])]

          const coord2D1 = this.to2D(debutDroite)
          const coord2D2 = this.to2D(finDroite)

          if (this.objets[k].visible) {
            if (this.objets[k].pointilles) {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1,
                pointilles: '6,6'
              })
            } else {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1
              })
            }
          }
        }
        break

      case 'demi-droite':
        {
          const coordext1 = this.objets[this.numeroObjet(o.ext1)].coord2
          const coordext2 = this.objets[this.numeroObjet(o.ext2)].coord2
          const t = 100
          const debutDroite = [coordext1[0], coordext1[1], coordext1[2]]
          const finDroite = [coordext1[0] + t * (coordext2[0] - coordext1[0]), coordext1[1] + t * (coordext2[1] - coordext1[1]), coordext1[2] + t * (coordext2[2] - coordext1[2])]

          const coord2D1 = this.to2D(debutDroite)
          const coord2D2 = this.to2D(finDroite)

          if (this.objets[k].visible) {
            if (this.objets[k].pointilles) {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1,
                pointilles: '6,6'
              })
            } else {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1
              })
            }
          }
        }
        break

      case 'plan':
        {
          const coordext1 = this.objets[this.numeroObjet(o.ext1)].coord2
          const coordext2 = this.objets[this.numeroObjet(o.ext2)].coord2
          const t = 100
          const debutDroite = [coordext1[0] - t * (coordext2[0] - coordext1[0]), coordext1[1] - t * (coordext2[1] - coordext1[1]), coordext1[2] - t * (coordext2[2] - coordext1[2])]
          const finDroite = [coordext1[0] + t * (coordext2[0] - coordext1[0]), coordext1[1] + t * (coordext2[1] - coordext1[1]), coordext1[2] + t * (coordext2[2] - coordext1[2])]

          const coord2D1 = this.to2D(debutDroite)
          const coord2D2 = this.to2D(finDroite)

          if (this.objets[k].visible) {
            if (this.objets[k].pointilles) {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1,
                pointilles: '6,6'
              })
            } else {
              j3pCreeSegment(this.svg, {
                id: this.idconteneur + 'segment' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1
              })
            }
          }
        }
        break

      case 'vecteur':
        {
          const coordext1 = this.objets[this.numeroObjet(o.ext1)].coord2
          const coordext2 = this.objets[this.numeroObjet(o.ext2)].coord2
          const coord2D1 = this.to2D(coordext1)
          const coord2D2 = this.to2D(coordext2)

          if (this.objets[k].visible) {
            if (this.objets[k].pointilles) {
              j3pCreeVecteur(this.svg, {
                numero: 0,
                id: this.idconteneur + 'vecteur' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1,
                pointilles: '6,6'
              })
            } else {
              j3pCreeVecteur(this.svg, {
                numero: 0,
                id: this.idconteneur + 'vecteur' + nom,
                x1: coord2D1[0],
                y1: coord2D1[1],
                x2: coord2D2[0],
                y2: coord2D2[1],
                couleur: this.objets[k].couleur,
                epaisseur: 3,
                opacite: 1
              })
            }
          }
        }
        break
    }
  }
}

_3D.prototype.ajoute = function (listeObjets) {
  for (let k = 0; k < listeObjets.length; k++) {
    if (typeof listeObjets[k].visible === 'undefined') {
      listeObjets[k].visible = true
    }
    this.objets.push(listeObjets[k])
  }
  this.construit()
}

_3D.prototype.tourne = function (coord) {
  let tempo = j3pRotation('Ox', this.rotation.Ox, coord)
  tempo = j3pRotation('Oy', this.rotation.Oy, tempo)
  tempo = j3pRotation('Oz', this.rotation.Oz, tempo)
  return tempo
}

_3D.prototype.numeroObjet = function (nom) {
  for (let k = 0; k < this.objets.length; k++) {
    if (this.objets[k].nom === nom) return k
  }
  return -1
}

/*
 nomsommets:["","A","","C","D","E","F","G","H"],
                sommetsvisibles:["",true,false,false,false,false,false,false,false]
 */
_3D.prototype.visible = function (nomObjet) {
  if (this.nomsommets.indexOf(nomObjet) !== -1) {
    this.sommetsvisibles[this.nomsommets.indexOf(nomObjet)] = true
    this.construit()
    return
  }
  const numero = this.numeroObjet(nomObjet)
  if (!this.objets[numero].visible) {
    this.objets[numero].visible = true
    this.construit()
  }
}

_3D.prototype.invisible = function (nomObjet) {
  if (this.nomsommets.indexOf(nomObjet) !== -1) {
    this.sommetsvisibles[this.nomsommets.indexOf(nomObjet)] = false
    this.construit()
    return
  }
  const numero = this.numeroObjet(nomObjet)
  if (this.objets[numero].visible) {
    this.objets[numero].visible = false
    this.construit()
  }
}

/*
 *
 * Rotation /t ch du point tab et d’angle angle
 */
export function j3pRotation (ch, angle, tab) {
  angle = (angle / 180) * Math.PI
  const res = []
  switch (ch) {
    case 'Ox':
      res[0] = tab[0]
      res[1] = tab[1] * Math.cos(angle) - tab[2] * Math.sin(angle)
      res[2] = tab[1] * Math.sin(angle) + tab[2] * Math.cos(angle)
      break
    case 'Oy':
      res[0] = tab[2] * Math.sin(angle) + tab[0] * Math.cos(angle)
      res[1] = tab[1]
      res[2] = tab[2] * Math.cos(angle) - tab[0] * Math.sin(angle)
      break
    case 'Oz':
      res[0] = tab[0] * Math.cos(angle) - tab[1] * Math.sin(angle)
      res[1] = tab[0] * Math.sin(angle) + tab[1] * Math.cos(angle)
      res[2] = tab[2]
      break
  }
  return res
}

/**
 * Retourne le produit vectoriel de deux vecteurs
 * (utilisé seulement dans 3D.js et Solide.js (ce dernier n’étant jamais chargé)
 * @param {number[]} v1
 * @param {number[]} v2
 * @return {number}
 */
export function j3pVectoriel (v1, v2) {
  const res = []
  res[0] = v1[1] * v2[2] - v1[2] * v2[1]
  res[1] = v1[2] * v2[0] - v1[0] * v2[2]
  res[2] = v1[0] * v2[1] - v1[1] * v2[0]
  return res
}

export function j3pScalaire3D (u, v) {
  return u[0] * v[0] + u[1] * v[1] + u[2] * v[2]
}

export function j3pVectNorme3D (u) {
  const norme = Math.sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2])
  return ([u[0] / norme, u[1] / norme, u[2] / norme])
}

export function j3pNorme3D (u) {
  return Math.sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2])
}

// mat = [[a11,a12,a13],[a21,a22,a23],[a31,a32,a33]]

export function j3pInverseMatrice (m) {
  const cofac00 = m[1][1] * m[2][2] - m[1][2] * m[2][1]
  const cofac01 = -(m[1][0] * m[2][2] - m[1][2] * m[2][0])
  const cofac02 = m[1][0] * m[2][1] - m[1][1] * m[2][0]
  const cofac10 = -(m[0][1] * m[2][2] - m[0][2] * m[2][1])
  const cofac11 = m[0][0] * m[2][2] - m[0][2] * m[2][0]
  const cofac12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1])
  const cofac20 = m[0][1] * m[1][2] - m[0][2] * m[1][1]
  const cofac21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2])
  const cofac22 = m[0][0] * m[1][1] - m[0][1] * m[1][0]
  const detm = m[0][0] * cofac00 + m[0][1] * cofac01 + m[0][2] * cofac02

  return [[cofac00 / detm, cofac10 / detm, cofac20 / detm], [cofac01 / detm, cofac11 / detm, cofac21 / detm], [cofac02 / detm, cofac12 / detm, cofac22 / detm]]
}

export function j3pProduitMatVec (m, tab) {
  return [m[0][0] * tab[0] + m[0][1] * tab[1] + m[0][2] * tab[2], m[1][0] * tab[0] + m[1][1] * tab[1] + m[1][2] * tab[2], m[2][0] * tab[0] + m[2][1] * tab[1] + m[2][2] * tab[2]]
}

export default _3D