objets/CRepere.js

/*
 * 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 StyleTrait from '../types/StyleTrait'
import Vect from '../types/Vect'
import { cens, indiceMiniMaxi, intersectionDroitesSecantes } from '../kernel/kernel'
import CElementLigne from './CElementLigne'
import CDroite from './CDroite'
import CValeur from './CValeur'
import { aligne } from 'src/kernel/kernelVect'

export default CRepere

/**
 * Classe représentant un repère.
 * @constructor
 * @extends CElementLigne
 * @param {CListeObjets} listeProprietaire  La liste propriétaire de l'objet
 * @param {CImplementationProto} impProto  null ou pointe sur la construction propriétaire de l'objet.
 * @param {boolean} estElementFinal  true si l'objet est un objet final de construction
 * @param {Color} couleur  La couleur de l'objet
 * @param {boolean} masque  true si le repère est masqué.
 * @param {StyleTrait} style  Le style de trait pour le quadrillage.
 * @param {CPt} o  L'origine du repère.
 * @param {CPt} i  Le point de coordonnées (1;0).
 * @param {CPt} j  Le point de coordonnées (0;1).
 * @param {CValeur} abscisseOrigine  L'abscisse à l'origine.
 * @param {CValeur} ordonneeOrigine  L'ordonnée à l'origine.
 * @param {boolean} quadrillageHorizontal  true pour des droites verticales de quadrillage.
 * @param {boolean} quadrillageVertical  true pour des droites horizontales de quadrillage.
 * @param {boolean} pointilles  true si on veut que les points à coordonnées entières soient représentés
 * par des petits points.
 * @param {CValeur} uniteX  L'unité sur l'axe des abcsisses.
 * @param {CValeur} uniteY  L'unité sur l'axe des ordonnées.
 * @returns {CRepere}
 */
function CRepere (listeProprietaire, impProto, estElementFinal, couleur,
  masque, style, o, i, j, abscisseOrigine, ordonneeOrigine,
  quadrillageHorizontal, quadrillageVertical, pointilles, uniteX, uniteY) {
  if (arguments.length === 1) CElementLigne.call(this, listeProprietaire)
  else {
    CElementLigne.call(this, listeProprietaire, impProto, estElementFinal, couleur,
      false, 0, 0, masque, '', 0, style)

    this.o = o
    this.i = i
    this.j = j
    this.abscisseOrigine = abscisseOrigine
    this.ordonneeOrigine = ordonneeOrigine
    this.quadrillageHorizontal = quadrillageHorizontal
    this.quadrillageVertical = quadrillageVertical
    this.pointilles = pointilles
    this.uniteX = uniteX
    this.uniteY = uniteY
    this.u = new Vect()
    this.v = new Vect()
    this.droiteQuadrillage = new CDroite(listeProprietaire)
    this.droiteQuadrillage.montre()
    this.origine = {}
    this.pointint = new Array(4)
    for (let k = 0; k < 4; k++) {
      this.pointint[k] = {}
    }
  }
  this.vect = new Vect()
}
CRepere.prototype = new CElementLigne()
CRepere.prototype.constructor = CRepere
CRepere.prototype.superClass = 'CElementLigne'
CRepere.prototype.className = 'CRepere'

CRepere.prototype.numeroVersion = function () {
  return 2
}

CRepere.prototype.setClone = function (ptel) {
  CElementLigne.prototype.setClone.call(this, ptel)
  this.absMiniH = ptel.absMiniH
  this.absMaxiH = ptel.absMaxiH
  this.absMiniV = ptel.absMiniV
  this.absMaxiV = ptel.absMaxiV
  this.infoSurRandom = ptel.infoSurRandom
  this.Dimf = ptel.Dimf
  this.origine.x = ptel.origine.x
  this.origine.y = ptel.origine.y
  ptel.u.setCopy(this.u)
  ptel.v.setCopy(this.v)
  this.unitex = ptel.unitex
  this.unitey = ptel.unitey
}
CRepere.prototype.getClone = function (listeSource, listeCible) {
  const ind1 = listeSource.indexOf(this.o)
  const ind2 = listeSource.indexOf(this.i)
  const ind3 = listeSource.indexOf(this.j)
  const ind4 = listeSource.indexOf(this.impProto)
  const abscisseOrigineClone = this.abscisseOrigine.getClone(listeSource, listeCible)
  const ordonneeOrigineClone = this.ordonneeOrigine.getClone(listeSource, listeCible)
  const uniteXclone = this.uniteX.getClone(listeSource, listeCible)
  const uniteYClone = this.uniteY.getClone(listeSource, listeCible)

  return new CRepere(listeCible, listeCible.get(ind4, 'CImplementationProto'),
    this.estElementFinal, this.couleur, this.masque, this.style.getClone(),
    listeCible.get(ind1, 'CPt'), listeCible.get(ind2, 'CPt'),
    listeCible.get(ind3, 'CPt'), abscisseOrigineClone, ordonneeOrigineClone, this.quadrillageHorizontal,
    this.quadrillageVertical, this.pointilles, uniteXclone, uniteYClone)
}
CRepere.prototype.initialisePourDependance = function () {
  CElementLigne.prototype.initialisePourDependance.call(this)
  this.abscisseOrigine.initialisePourDependance()
  this.ordonneeOrigine.initialisePourDependance()
  this.uniteX.initialisePourDependance()
  this.uniteY.initialisePourDependance()
}
CRepere.prototype.depDe = function (p) {
  if (this.elementTestePourDependDe === p) return this.dependDeElementTeste
  return this.memDep(CElementLigne.prototype.depDe.call(this, p) ||
  this.o.depDe(p) || this.i.depDe(p) || this.j.depDe(p) ||
  this.abscisseOrigine.depDe(p) || this.ordonneeOrigine.depDe(p) ||
  this.uniteX.depDe(p) || this.uniteY.depDe(p))
}
CRepere.prototype.dependDePourBoucle = function (p) {
  return (p === this) ||
  this.o.dependDePourBoucle(p) || this.i.dependDePourBoucle(p) || this.j.dependDePourBoucle(p) ||
  this.abscisseOrigine.dependDePourBoucle(p) || this.ordonneeOrigine.dependDePourBoucle(p) ||
  this.uniteX.dependDePourBoucle(p) || this.uniteY.dependDePourBoucle(p)
}
CRepere.prototype.nomIndispensable = function (el) {
  return ((el === this.o) || (el === this.i) || (el === this.j))
}
CRepere.prototype.positionne = function (infoRandom, dimfen) {
  this.uniteX.positionne(infoRandom, dimfen)
  this.uniteY.positionne(infoRandom, dimfen)
  this.unitex = this.uniteX.rendValeur()
  this.unitey = this.uniteY.rendValeur()

  this.abscisseOrigine.positionne(infoRandom, dimfen)
  this.ordonneeOrigine.positionne(infoRandom, dimfen)
  this.existe = (this.o.existe) && (this.i.existe) && (this.j.existe) &&
    this.abscisseOrigine.existe && this.ordonneeOrigine.existe &&
    this.uniteX.existe && this.uniteY.existe &&
    (this.unitex > 0) && (this.unitey > 0) &&
    !(aligne(this.x, this.o.y, this.i.x, this.i.y, this.j.x, this.j.y))
  if (this.existe) {
    // On mémorise les valeurs de l'abscisse à l'origine et de l'ordonnée à l'origine.
    this.valAbscisseOrigine = this.abscisseOrigine.rendValeur()
    this.valOrdonneeOrigine = this.ordonneeOrigine.rendValeur()
    const abs = new Array(4)
    const pointIndices = { x: 0, y: 0 } // Contiendra les indices des valeurs minimalse et maximales
    // Java : différence par rapport au C++. Nécessaire de mémoriser infoRandom et dimfen
    // pour lengthtracé de la droite servant au quadrillage
    this.infoSurRandom = infoRandom
    this.dimf = dimfen
    this.u.setVecteur(this.o, this.i)
    this.v.setVecteur(this.o, this.j)
    // On calcule les réelles coordonnées de l'origine
    this.origine.x = this.o.x - this.u.x * this.valAbscisseOrigine / this.unitex - this.v.x * this.valOrdonneeOrigine / this.unitey
    this.origine.y = this.o.y - this.u.y * this.valAbscisseOrigine / this.unitex - this.v.y * this.valOrdonneeOrigine / this.unitey
    // Préparation du quadrillage vertical éventuel;
    if (this.quadrillageVertical || this.pointilles) {
      intersectionDroitesSecantes(0, 0, this.u, this.o.x, this.o.y, this.v, this.pointint[0])
      intersectionDroitesSecantes(0, dimfen.y, this.u, this.o.x, this.o.y, this.v, this.pointint[1])
      intersectionDroitesSecantes(dimfen.x, 0, this.u, this.o.x, this.o.y, this.v, this.pointint[2])
      intersectionDroitesSecantes(dimfen.x, dimfen.y,
        this.u, this.o.x, this.o.y, this.v, this.pointint[3])
      if (this.v.y !== 0) {
        abs[0] = (this.pointint[0].y - this.o.y) / this.v.y
        abs[1] = (this.pointint[1].y - this.o.y) / this.v.y
        abs[2] = (this.pointint[2].y - this.o.y) / this.v.y
        abs[3] = (this.pointint[3].y - this.o.y) / this.v.y
      } else {
        abs[0] = (this.pointint[0].x - this.o.x) / this.v.x
        abs[1] = (this.pointint[1].x - this.o.x) / this.v.x
        abs[2] = (this.pointint[2].x - this.o.x) / this.v.x
        abs[3] = (this.pointint[3].x - this.o.x) / this.v.x
      }
      indiceMiniMaxi(3, abs, pointIndices)
      this.absMiniV = Math.floor(abs[pointIndices.x] + 1)
      this.absMaxiV = Math.floor(abs[pointIndices.y])
    }
    if (this.quadrillageHorizontal || this.pointilles) {
      intersectionDroitesSecantes(0, 0, this.v, this.o.x, this.o.y, this.u, this.pointint[0])
      intersectionDroitesSecantes(0, dimfen.y, this.v, this.o.x, this.o.y, this.u, this.pointint[1])
      intersectionDroitesSecantes(dimfen.x, 0, this.v, this.o.x, this.o.y, this.u, this.pointint[2])
      intersectionDroitesSecantes(dimfen.x, dimfen.y, this.v, this.o.x, this.o.y, this.u, this.pointint[3])
      if (this.u.x !== 0) {
        abs[0] = (this.pointint[0].x - this.o.x) / this.u.x
        abs[1] = (this.pointint[1].x - this.o.x) / this.u.x
        abs[2] = (this.pointint[2].x - this.o.x) / this.u.x
        abs[3] = (this.pointint[3].x - this.o.x) / this.u.x
      } else {
        abs[0] = (this.pointint[0].y - this.o.y) / this.u.y
        abs[1] = (this.pointint[1].y - this.o.y) / this.u.y
        abs[2] = (this.pointint[2].y - this.o.y) / this.u.y
        abs[3] = (this.pointint[3].y - this.o.y) / this.u.y
      }
      indiceMiniMaxi(3, abs, pointIndices)
      this.absMiniH = Math.floor(abs[pointIndices.x] + 1)
      this.absMaxiH = Math.floor(abs[pointIndices.y])
    }
  }
}
CRepere.prototype.createg = function () {
  let p, q, x1, y1, cerc, style, styleCer, path
  const g = cens('g')
  style = ''
  // coul = this.couleur.rgb() Modifié version 4.9.9.4
  const coul = this.color
  const stroke = this.style.stroke
  if (stroke.length !== 0) style += 'stroke-dasharray:' + stroke + ';'
  const strokewidth = this.style.strokeWidth
  style += 'stroke-width:' + strokewidth + ';'
  style += 'stroke:' + coul + ';'
  let d = ''
  if (this.quadrillageVertical) {
    this.droiteQuadrillage.donneCouleur(this.couleur)
    this.droiteQuadrillage.donneStyle(this.style) // Contrairement à la version java les repères ont un style
    // if (this.absMaxiV - this.absMiniV <= 200) { // Modifié version 6.3.0 pour gagner en rapidité
    if (this.absMaxiV - this.absMiniV <= 100) {
      this.droiteQuadrillage.vect.x = this.u.x
      this.droiteQuadrillage.vect.y = this.u.y
      for (p = this.absMiniV; p <= this.absMaxiV; p++) {
        if (p !== 0) {
          this.droiteQuadrillage.point_x = this.o.x + p * this.v.x
          this.droiteQuadrillage.point_y = this.o.y + p * this.v.y
          // Les paramètres d'appel ne servent pas.
          this.droiteQuadrillage.positionne(this.infoSurRandom, this.dimf)
          d += 'M' + this.droiteQuadrillage.xext1 + ' ' + this.droiteQuadrillage.yext1
          d += 'L' + this.droiteQuadrillage.xext2 + ' ' + this.droiteQuadrillage.yext2
        }
      }
    }
  }
  if (this.quadrillageHorizontal) {
    this.droiteQuadrillage.donneCouleur(this.couleur)
    this.droiteQuadrillage.donneStyle(this.style)
    // if (this.absMaxiH - this.absMiniH <= 200) { // Modifié version 6.3.0 pour gagner en rapidité
    if (this.absMaxiH - this.absMiniH <= 100) {
      this.droiteQuadrillage.vect.x = this.v.x
      this.droiteQuadrillage.vect.y = this.v.y
      for (p = this.absMiniH; p <= this.absMaxiH; p++) {
        if (p !== 0) {
          this.droiteQuadrillage.point_x = this.o.x + p * this.u.x
          this.droiteQuadrillage.point_y = this.o.y + p * this.u.y
          this.droiteQuadrillage.positionne(this.infoSurRandom, this.dimf)
          d += 'M' + this.droiteQuadrillage.xext1 + ' ' + this.droiteQuadrillage.yext1
          d += 'L' + this.droiteQuadrillage.xext2 + ' ' + this.droiteQuadrillage.yext2
        }
      }
    }
  }
  if (d.length !== 0) {
    path = cens('path', {
      d,
      style
    })
    g.appendChild(path)
  }
  if (this.pointilles) {
    /* Modifié version 5.0
    stroke = StyleTrait.stroke(StyleTrait.traitFin);
    styleCer = "stroke-dasharray:"+stroke+";"+"stroke-width:1"+"stroke:"+coul+";"+"fill:"+coul;
    */
    styleCer = 'stroke-width:1;stroke:' + coul + ';' + 'fill:' + coul + ';'
    // Modifié version 6.3.0 pour gagner en rapidité
    // if ((this.absMaxiH - this.absMiniH <= 200)&& (this.absMaxiV - this.absMiniV <= 200)) {
    if ((this.absMaxiH - this.absMiniH <= 100) && (this.absMaxiV - this.absMiniV <= 100)) {
      for (p = this.absMiniH; p <= this.absMaxiH; p++) {
        for (q = this.absMiniV; q <= this.absMaxiV; q++) {
          x1 = this.o.x + p * this.u.x + q * this.v.x
          y1 = this.o.y + p * this.u.y + q * this.v.y
          cerc = cens('circle', {
            style: styleCer,
            cx: x1,
            cy: y1,
            // r : 1 // Modifié version 5.4
            r: 0.5
          })
          g.appendChild(cerc)
        }
      }
    }
  }
  // Ligne suivante modifiée version 6.5.2
  // g.setAttribute('pointer-events', 'none')
  g.setAttribute('pointer-events', this.pointerevents)
  return g
}
CRepere.prototype.trace = function (svg) {
  const g = this.createg()
  g.setAttribute('id', this.id)
  svg.appendChild(g)
  this.g = g
}
CRepere.prototype.update = function (svg) {
  const oldg = this.g
  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
}
CRepere.prototype.confonduAvec = function (p) {
  if (p.className === this.className) return (this.o === p.o) && (this.i === p.i) && (this.j === p.j)
  else return false
}
CRepere.prototype.remplacePoint = function (ancienPoint, nouveauPoint) {
  if (this.o === ancienPoint) this.o = nouveauPoint
  if (this.i === ancienPoint) this.i = nouveauPoint
  if (this.j === ancienPoint) this.j = nouveauPoint
}
CRepere.prototype.getNatureCalcul = function () {
  return NatCal.NRepere
}
CRepere.prototype.getNature = function () {
  return NatObj.NRepere
}
CRepere.prototype.ajouteAntecedents = function (liste) {
  liste.add(this.o)
  liste.add(this.i)
  liste.add(this.j)
}
/**
 * Fonction renvoyant les coordonnées absolues d'un point de coordonnées (abs, ord) dans le repère
 * @param {number} abs
 * @param {number} ord
 * @returns {number[]} les coordonnées [x, y]
 */
CRepere.prototype.getAbsCoord = function (abs, ord) {
  const vec = new Vect()
  const unitex = this.unitex
  const unitey = this.unitey
  vec.x = abs * this.u.x / unitex + ord * this.v.x / unitey
  vec.y = abs * this.u.y / unitex + ord * this.v.y / unitey
  return [this.origine.x + vec.x, this.origine.y + vec.y]
}
/**
 * Fonction renvoyant les coordonnées dans le repère d'un point de coordonnées absolues (x, y)
 * @param {number}x
 * @param {number} y
 * @returns {number[]}
 */
CRepere.prototype.getCoord = function (x, y) {
  const ux = this.u.x
  const uy = this.u.y
  const vx = this.v.x
  const vy = this.v.y
  const d = ux * vy - uy * vx
  const ox = this.o.x
  const oy = this.o.y
  const x2 = x - ox
  const y2 = y - oy
  return [(vy * x2 - vx * y2) / d, (ux * y2 - uy * x2) / d]
}

CRepere.prototype.read = function (inps, list) {
  CElementLigne.prototype.read.call(this, inps, list)
  this.abscisseOrigine = new CValeur(list, 0)
  this.ordonneeOrigine = new CValeur(list, 0)
  this.u = new Vect()
  this.v = new Vect()
  this.droiteQuadrillage = new CDroite(list)
  this.droiteQuadrillage.donneStyle(StyleTrait.traitPointille)
  this.droiteQuadrillage.montre()
  this.origine = { x: 0, y: 0 }
  this.pointint = new Array(4)
  // Créer le tableau ne suffit pas, il faut instancier chaque membre
  for (let i = 0; i < 4; i++) this.pointint[i] = { x: 0, y: 0 }
  const ind1 = inps.readInt()
  const ind2 = inps.readInt()
  const ind3 = inps.readInt()
  this.o = list.get(ind1, 'CPt')
  this.i = list.get(ind2, 'CPt')
  this.j = list.get(ind3, 'CPt')
  this.quadrillageVertical = inps.readBoolean()
  this.quadrillageHorizontal = inps.readBoolean()
  this.pointilles = inps.readBoolean()
  this.abscisseOrigine = new CValeur()
  this.abscisseOrigine.read(inps, list)
  this.ordonneeOrigine = new CValeur()
  this.ordonneeOrigine.read(inps, list)
  // Ajout version 3.9.5 : unité sur l'axe des abscisses et l'axe des ordonnées
  if (this.nVersion >= 2) {
    this.uniteX = new CValeur()
    this.uniteX.read(inps, list)
    this.uniteY = new CValeur()
    this.uniteY.read(inps, list)
  } else {
    this.uniteX = new CValeur(list, 1)
    this.uniteY = new CValeur(list, 1)
  }
}
CRepere.prototype.write = function (oups, list) {
  CElementLigne.prototype.write.call(this, oups, list)
  // Créer le tableau ne suffit pas, il faut instancier chaque membre
  // for (var i = 0; i < 4; i++) this.pointint[i] = { x: 0, y: 0 };
  const ind1 = list.indexOf(this.o)
  oups.writeInt(ind1)
  const ind2 = list.indexOf(this.i)
  oups.writeInt(ind2)
  const ind3 = list.indexOf(this.j)
  oups.writeInt(ind3)
  oups.writeBoolean(this.quadrillageVertical)
  oups.writeBoolean(this.quadrillageHorizontal)
  oups.writeBoolean(this.pointilles)
  this.abscisseOrigine.write(oups, list)
  this.ordonneeOrigine.write(oups, list)
  this.uniteX.write(oups, list)
  this.uniteY.write(oups, list)
}