/*
* Created by yvesb on 10/10/2016.
*/
/*
* 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 CListeObjets from '../objets/CListeObjets'
import Pointeur from '../types/Pointeur'
import NatObj from '../types/NatObj'
import NatCal from '../types/NatCal'
import Nat from '../types/Nat'
import CPointBase from '../objets/CPointBase'
import CPointLieDroite from '../objets/CPointLieDroite'
import Color from '../types/Color'
import MotifPoint from '../types/MotifPoint'
import CDroite from '../objets/CDroite'
import CDroiteDirectionFixe from '../objets/CDroiteDirectionFixe'
import CDroiteAB from '../objets/CDroiteAB'
import CDroitePerpendiculaire from '../objets/CDroitePerpendiculaire'
import CCercleOA from '../objets/CCercleOA'
import CIntDroiteCercle from '../objets/CIntDroiteCercle'
import CPointLieBipoint from '../objets/CPointLieBipoint'
import CRepere from '../objets/CRepere'
import CLongueur from '../objets/CLongueur'
import StyleTrait from '../types/StyleTrait'
import StyleFleche from '../types/StyleFleche'
import CLatex from '../objets/CLatex'
import StyleEncadrement from '../types/StyleEncadrement'
import CAffLiePt from '../objets/CAffLiePt'
import CPointLieCercle from '../objets/CPointLieCercle'
import CVecteur from '../objets/CVecteur'
import CCalcConst from '../objets/CCalcConst'
import { getStr, zero } from '../kernel/kernel'
import PositionDroites from '../types/PositionDroites'
import PositionDroiteCercle from '../types/PositionDroiteCercle'
import PositionCercleCercle from '../types/PositionCercleCercle'
import CSegment from '../objets/CSegment'
import CCommentaire from '../objets/CCommentaire'
import CDemiDroiteOA from '../objets/CDemiDroiteOA'
import CTranslation from '../objets/CTranslation'
import CMesureX from '../objets/CMesureX'
import CAppelFonction from '../objets/CAppelFonction'
import CPointDansRepere from '../objets/CPointDansRepere'
import CResultatValeur from '../objets/CResultatValeur'
import InfoLieu from '../types/InfoLieu'
import CLieuDePoints from '../objets/CLieuDePoints'
import CCalcul from '../objets/CCalcul'
import CValeur from '../objets/CValeur'
import CPointImage from '../objets/CPointImage'
import CConstante from '../objets/CConstante'
import COperation from '../objets/COperation'
import CHomothetie from '../objets/CHomothetie'
import Ope from '../types/Ope'
/// //////////////////////////////////////////////////////////
// Constantes importées pour le protocole de la figure
import CAbscisseOrigineRep from '../objets/CAbscisseOrigineRep'
import COrdonneeOrigineRep from '../objets/COrdonneeOrigineRep'
import CUnitexRep from '../objets/CUnitexRep'
import CUniteyRep from '../objets/CUniteyRep'
import CArcDeCercleAncetre from '../objets/CArcDeCercleAncetre'
import CCercle from '../objets/CCercle'
import CDemiDroite from '../objets/CDemiDroite'
import CDemiPlan from '../objets/CDemiPlan'
import CEditeurFormule from '../objets/CEditeurFormule'
import CGrapheSuiteRec from '../objets/CGrapheSuiteRec'
import CGrapheSuiteRecComplexe from '../objets/CGrapheSuiteRecComplexe'
import CImage from '../objets/CImage'
import CLieuDeBase from '../objets/CLieuDeBase'
import CLieuDiscretDeBase from '../objets/CLieuDiscretDeBase'
import CLieuObjetAncetre from '../objets/CLieuObjetAncetre'
import CMacro from '../objets/CMacro'
import CMarqueAngleAncetre from '../objets/CMarqueAngleAncetre'
import CMarqueSegment from '../objets/CMarqueSegment'
import CPt from '../objets/CPt'
import CDroiteAncetre from '../objets/CDroiteAncetre'
import CSurface from '../objets/CSurface'
import CValeurAffichee from '../objets/CValeurAffichee'
import ConfirmDlg from '../dialogs/ConfirmDlg'
import { intersection, intersectionCercleCercle, intersectionDroiteCercle } from 'src/kernel/kernelVect'
import addQueue from 'src/kernel/addQueue'
import CImplementationProto from 'src/objets/CImplementationProto'
export default CListeObjets
CListeObjets.prototype.depDe4Rec = function (el) {
for (const elb of this.col) {
if (elb.depDe4Rec(el)) return true
}
return false
}
CListeObjets.prototype.detruitDerniersElements = function (n) {
for (let i = 0; i < n; i++) {
this.detruitDernierObjet()
}
}
/**
* Fonction ajoutant la courbe de la fonction f sur droiteIntervalle (qui peut être une droite, un segment ou uen demi-droite)
* @param {CRepere} repere le repère dans lequel est tracée la courbe
* @param {CDroite|CDemiDroite} droiteIntervalle
* @param {CFonc} fonction la fonction réelle d'une variable dont on trace la courbe
* @param {string} nomPointLieAxe
* @param {string} nomCalculAbscisse
* @param {string} nomCalculOrdonnee
* @param {number} nombrePoints Nombre de points de la courbe (lieu de points)
* @param {boolean} pointLieCache true si le point lié de la corube est caché
* @param {boolean} pointCourbeCache true si le point gnérant la courbe est cahcé
* @param {boolean} gestionAutoDiscontinuite true pour une gestion auto des discontinuités
* @param {Color} couleur couleur de la courbe
* @param {StyleTrait} lineStyle le style de trait
* @param {number} taillePoliceNom taille de la police pour les noms des points créés
* @param {MtgApp|null} app si null appel depuis l'API
* @returns {boolean} renvoie true si la courbe est visible. Si app est non nul, return non utilisé.
*/
CListeObjets.prototype.ajouteCourbe = function (repere, droiteIntervalle, fonction,
nomPointLieAxe, nomCalculAbscisse, nomCalculOrdonnee, nombrePoints,
pointLieCache, pointCourbeCache, gestionAutoDiscontinuite,
couleur, lineStyle, taillePoliceNom, app = null) {
// On génère une abscisse aléatoire pour le point lié à l'axe des
// abscisses
let abs1 = droiteIntervalle.abscisseMinimale()
let abs2 = droiteIntervalle.abscisseMaximale()
const d = abs2 - abs1
const bl = Color.black
abs1 = abs1 + d / 10
abs2 = abs2 - d / 10
const abs = abs1 + (abs2 - abs1) * Math.random()
// var pointLieDroite = new CPointLieDroite(listePr, null, false, Color.black, false, 0d, 0d,
// pointLieCache, nomPointLieAxe, frame.pref_indiceTaillePoliceNom, MotifPoint.PetitRond, true, abs,
// droiteIntervalle, false);
const pointLieDroite = new CPointLieDroite(this, null, false, bl, false, 0, 3, pointLieCache, '', taillePoliceNom,
MotifPoint.petitRond, false, false, abs, droiteIntervalle)
pointLieDroite.donneNom(nomPointLieAxe)
this.add(pointLieDroite)
// On crée la mesure de l'abscisse du point qu'on vient de créer
// Modifié version 5.0
const calculAbscisse = new CMesureX(this, null, false, nomCalculAbscisse, repere, pointLieDroite)
this.add(calculAbscisse)
const ordonnee = new CAppelFonction(this, fonction, new CResultatValeur(this, calculAbscisse))
const calculOrdonnee = new CCalcul(this, null, false, nomCalculOrdonnee, ordonnee.chaineCalculSansPar(null), ordonnee)
this.add(calculOrdonnee)
// Il faut maintenant créer le point repéré de la courbe dont
// les positions successives généreront cette courbe
const pointCourbe = new CPointDansRepere(this, null, false, bl, false, 0, 3, pointCourbeCache, '', taillePoliceNom,
MotifPoint.petitRond, false, repere, new CValeur(this, new CResultatValeur(this, calculAbscisse)),
new CValeur(this, new CResultatValeur(this, calculOrdonnee)))
this.add(pointCourbe)
// Il faut maintenant créer la courbe comme un lieu de points
const infoLieu = new InfoLieu(nombrePoints, false, gestionAutoDiscontinuite)
const lieu = new CLieuDePoints(this, null, false, couleur, false, lineStyle, pointCourbe,
infoLieu, pointLieDroite)
this.add(lieu)
lieu.etablitListeElementsAncetres()
// On regarde si le lieu créé est visible
const dimf = this.documentProprietaire.dimf
this.positionne(false, dimf)
const ret = lieu.dansFen(dimf)
if (!ret) {
if (app) {
new ConfirmDlg(app, 'Lieuhf', null, function () {
app.detruitDerniersElements(6) // A appeler sur app au lieu de this à cause gestiond es constructions
})
} else {
this.detruitDerniersElements(6)
}
}
return ret // Sert pour appel depuis l'API
}
/**
* Ajoute dans le repère repere la courbe d'une fonction sur la partie visible de l'axe des abscisses
* @param repere Le repère dans lequel la courbe doit être tracée
* @param fonction La fonction dont la courbe doit être tracée
* @param nomPointLieAxe Le nom du point lié à l'axe (qui doit êgtre ici un segment)
* @param nomCalculAbscisse Le nom de la mesure de l'abscisse de ce point lié
* @param nomCalculOrdonnee Le nom de l'image de l'abscisse par la fonction
* @param nombrePoints Le nomnbre de points de la courbe
* @param pointLieCache true si le point lié doit être caché
* @param pointCourbeCache true su le point générateur de la courbe doit être caché
* @param gestionAutoDiscontinuite true pour une gestion auto des discontinuités de la courbe
* @param {Color} color couleur de la courbe
* @param {StyleTrait} lineStyle le style de trait de la courbe
* @param {number} taillePoliceNom la taille de police utilisée pour les noms créés
* @param {MtgApp} app L'application propriétaire. Si nul l'appel se fait depuis l'API
* @return {boolean} true si la courbe (lieu de points) est visible
*/
CListeObjets.prototype.ajouteCourbeSurR = function (repere, fonction, nomPointLieAxe, nomCalculAbscisse,
nomCalculOrdonnee, nombrePoints, pointLieCache, pointCourbeCache, gestionAutoDiscontinuite,
color, lineStyle, taillePoliceNom, app = null) {
// On regarde si le repère possède déjà un axe des abscisses
let axe = this.existeDroiteABDefiniePar(repere.o, repere.i)
if (axe === null) {
// axe = new CDroiteAB(frame.cadreActif().listePr, null, false, Color.black, StyleTrait.traitFin, repere.O, repere.I,
// frame.pref_indiceTaillePoliceNom);
axe = new CDroiteAB(this, null, false, Color.black, false, 0, 0, false, '', taillePoliceNom, lineStyle,
CDroite.abscisseNomParDefaut, repere.o, repere.i)
this.add(axe)
}
return this.ajouteCourbe(repere, axe, fonction, nomPointLieAxe, nomCalculAbscisse, nomCalculOrdonnee, nombrePoints,
pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, color, lineStyle, taillePoliceNom, app)
}
/**
* Ajoute dans le repère repere la courbe d'une fonction sur l'intervalle [a;b]
* @param repere Le repère dans lequel la courbe doit être tracée
* @param fonction La fonction dont la courbe doit être tracée
* @param nomPointLieAxe Le nom du point lié à l'axe (qui doit êgtre ici un segment)
* @param nomCalculAbscisse Le nom de la mesure de l'abscisse de ce point lié
* @param nomCalculOrdonnee Le nom de l'image de l'abscisse par la fonction
* @param nombrePoints Le nomnbre de points de la courbe
* @param pointLieCache true si le point lié doit être caché
* @param pointCourbeCache true su le point générateur de la courbe doit être caché
* @param gestionAutoDiscontinuite true pour une gestion auto des discontinuités de la courbe
* @param a Un CValeur contenant la valeur de a
* @param b Un CValeur contenant la valeur de b
* @param {Color} color couleur de la courbe
* @param {StyleTrait} lineStyle le style de trait de la courbe
* @param {number} taillePoliceNom la taille de police utilisée pour les noms créés
* @param {MtgApp} app L'application propriétaire. Si nul l'appel se fait depuis l'API
* @return {boolean} true si la courbe (lieu de points) est visible
*/
CListeObjets.prototype.ajouteCourbeSurab = function (repere, fonction, nomPointLieAxe, nomCalculAbscisse,
nomCalculOrdonnee, nombrePoints, pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, a, b,
color, lineStyle, taillePoliceNom, app = null) {
// On regarde si le repère possède déjà un axe des abscisses
let pta = a.existePtAbs(this, repere)
if (pta === null) {
pta = new CPointDansRepere(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, repere, a, new CValeur(this, 0))
this.add(pta)
}
let ptb = b.existePtAbs(this, repere)
if (ptb === null) {
ptb = new CPointDansRepere(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, repere, b, new CValeur(this, 0))
this.add(ptb)
}
const seg = new CSegment(this, null, false, Color.black, false, lineStyle, pta, ptb)
this.add(seg)
return this.ajouteCourbe(repere, seg, fonction, nomPointLieAxe, nomCalculAbscisse, nomCalculOrdonnee, nombrePoints,
pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, color, lineStyle, taillePoliceNom, app)
}
/**
* Fonction ajoutant dans le repère repere la courbe d'une fonction sur l'intervalle [a;+infini[
* @param {MtgApp} app Application propriétaire
* @param {CRepere} repere Le repère dans lequel la courbe doit être tracée
* @param {CFonc} fonction La fonction dont la courbe doit être tracée
* @param {string} nomPointLieAxe Le nom du point lié à l'axe (qui doit être ici un segment)
* @param {string} nomCalculAbscisse Le nom de la mesure de l'abscisse de ce point lié
* @param {string} nomCalculOrdonnee Le nom de l'image de l'abscisse par la fonction
* @param {number} nombrePoints Le nombre de points de la courbe
* @param {boolean} pointLieCache true si le point lié doit être caché
* @param {boolean} pointCourbeCache true su le point générateur de la courbe doit être caché
* @param {boolean} gestionAutoDiscontinuite true pour une gestion auto des discontinuités de la courbe
* @param {CValeur} a Un CValeur contenant la valeur de a
* @param {Color} color couleur de la courbe
* @param {StyleTrait} lineStyle le style de trait de la courbe
* @param {number} taillePoliceNom la taille de police utilisée pour les noms créés
* @param {MtgApp} app L'application propriétaire. Si nul l'appel se fait depuis l'API
* @return {boolean} true si la courbe (lieu de points) est visible
*/
CListeObjets.prototype.ajouteCourbeSuraInf = function (repere, fonction, nomPointLieAxe, nomCalculAbscisse,
nomCalculOrdonnee, nombrePoints, pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, a,
color, lineStyle, taillePoliceNom, app = null) {
// On regarde si le repère possède déjà un axe des abscisses
let pta = a.existePtAbs(this, repere)
if (pta === null) {
pta = new CPointDansRepere(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, repere, a, new CValeur(this, 0))
this.add(pta)
}
const trans = new CTranslation(this, null, false, repere.o, repere.i)
this.add(trans)
const ptim = new CPointImage(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, pta, trans)
this.add(ptim)
const ddte = new CDemiDroiteOA(this, null, false, Color.black, false, StyleTrait.stfc(this), pta, ptim)
this.add(ddte)
return this.ajouteCourbe(repere, ddte, fonction, nomPointLieAxe, nomCalculAbscisse, nomCalculOrdonnee, nombrePoints,
pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, color, lineStyle, taillePoliceNom, app)
}
/**
* Fonction ajoutant dans le repère repere la courbe d'une fonction sur l'intervalle ]-infini;a]
* @param {MtgApp} app L'application propriétaire
* @param repere Le repère dans lequel la courbe doit être tracée
* @param fonction La fonction dont la courbe doit être tracée
* @param nomPointLieAxe Le nom du point lié à l'axe (qui doit êgtre ici un segment)
* @param nomCalculAbscisse Le nom de la mesure de l'abscisse de ce point lié
* @param nomCalculOrdonnee Le nom de l'image de l'abscisse par la fonction
* @param nombrePoints Le nomnbre de points de la courbe
* @param pointLieCache true si le point lié doit être caché
* @param pointCourbeCache true su le point générateur de la courbe doit être caché
* @param gestionAutoDiscontinuite true pour une gestion auto des discontinuités de la courbe
* @param a Un CValeur contenant la valeur de a
* @param {Color} color couleur de la courbe
* @param {StyleTrait} lineStyle le style de trait de la courbe
* @param {number} taillePoliceNom la taille de police utilisée pour les noms créés
* @param {MtgApp} app L'application propriétaire. Si nul l'appel se fait depuis l'API
* @return {boolean} true si la courbe (lieu de points) est visible
*/
CListeObjets.prototype.ajouteCourbeSurInfa = function (repere, fonction, nomPointLieAxe, nomCalculAbscisse,
nomCalculOrdonnee, nombrePoints, pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, a,
color, lineStyle, taillePoliceNom, app = null) {
// On regarde si le repère possède déjà un axe des abscisses
let pta = a.existePtAbs(this, repere)
if (pta === null) {
pta = new CPointDansRepere(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, repere, a, new CValeur(this, 0))
this.add(pta)
}
const trans = new CTranslation(this, null, false, repere.i, repere.o)
this.add(trans)
const ptim = new CPointImage(this, null, false, Color.black, false, 3, 0, false, '', taillePoliceNom,
MotifPoint.petitRond, false, pta, trans)
this.add(ptim)
const ddte = new CDemiDroiteOA(this, null, false, Color.black, false, StyleTrait.stfc(this), pta, ptim)
this.add(ddte)
return this.ajouteCourbe(repere, ddte, fonction, nomPointLieAxe, nomCalculAbscisse, nomCalculOrdonnee, nombrePoints,
pointLieCache, pointCourbeCache, gestionAutoDiscontinuite, color, lineStyle, taillePoliceNom, app)
}
/**
* Fonction renvoyant un objet formé d'éléments de la liste du type d'objet graphique nat
* qui ne sont pas des objest intermédiaires de construction
* pointeurs : tableau contenant des pointeurs sur les objets trouvés
* noms : tableau contenant les noms des onjets correspondant
* @param {MtgApp} app L'application MtgApp propriétaire
* @param nat Nature des objets à afficher
* @param indmax Indice du dernier objet à afficher (-1 pour afficher tous les objets compatibles)
* @param exclu éventuel objet à ne pas faire figurer dans la liste
* @returns {{pointeurs: CElementBase[], noms: string[]}}
*/
CListeObjets.prototype.listeParNatCal = function (app, nat, indmax, exclu = null) {
let i; let el; let valide
const pointeurs = []
const noms = []
const indfin = indmax === -1 ? this.longueur() - 1 : indmax
for (i = 0; i <= indfin; i++) {
el = this.get(i)
valide = (el !== exclu) && !el.estElementIntermediaire() && el.estDeNatureCalcul(nat)
if (app.estExercice) valide = (valide && (app.listePourConst.indexOf(el) !== -1)) || app.calculOKForConst(el)
if (valide) {
pointeurs.push(el)
noms.push(el.getNom())
}
}
return { pointeurs, noms }
}
/**
* Fonctions renvoyant un objet formé de deux arrays contenant des pointeurs vers les macros pouvant être une macro de démarrage
* et leurs intitulés respectifs. Le premier élément de la liste est un pointeur null
* @returns {{pointeurs: CElementBase, noms: string[]}}
*/
CListeObjets.prototype.listeMacPourDem = function () {
const pointeurs = [null]
const noms = [getStr('NoMac')]
for (const el of this.col) {
if (el.estDeNature(NatObj.NMacro) && el.utilisablePourDemarrage()) {
pointeurs.push(el)
noms.push(el.intitule)
}
}
return { pointeurs, noms }
}
CListeObjets.prototype.listePourHist = function (indstart, objetsInterm, nbObj) {
const pointeurs = []
const noms = []
// var masked = []; // Contiendra l'état de masquage de chaque objet. Il doit être mémorisé
const maskedNames = [] // Contiendra l'état de masquage du nom de chaque point ou droite
// car lors du clignotement des objets en cours, leur statut peut changer, masqué ou non
for (let i = indstart; i <= nbObj; i++) {
const el = this.get(i)
if ((!el.estElementIntermediaire() || objetsInterm) && el.estVisibleDansHist()) {
pointeurs.push(el)
const info = el.info()
// if (el.estElementIntermediaire() && el.getNatureCalcul().isNotZero()) info = "*" + info;
noms.push(info)
// masked.push(el.estDeNature(NatObj.NTtObj) ? el.masque : null);
maskedNames.push(el.estDeNature(NatObj.NObjNommable) ? el.nomMasque : null)
}
}
return { pointeurs, noms, namemaskstate: maskedNames }
}
CListeObjets.prototype.contientDeriveeDe = function (fonc) {
for (const elb of this.col) {
if (elb.estDeNatureCalcul(NatCal.NDerivee) && !elb.estElementIntermediaire()) {
if (elb.fonctionAssociee === fonc) return true
}
}
return false
}
CListeObjets.prototype.listeFonctionsReellesSansDerivees = function (indmax, fonctionARajouter) {
const pointeurs = []
const noms = []
const indfin = indmax === -1 ? this.longueur() - 1 : indmax
for (let i = 0; i <= indfin; i++) {
const el = this.get(i)
if (el.estDeNatureCalcul(NatCal.NFoncR1Var) && !el.estElementIntermediaire()) {
if ((!this.contientDeriveeDe(el) && el.calcul.deriveePossible(0)) || (el === fonctionARajouter)) {
pointeurs.push(el)
noms.push(el.getNom())
}
}
}
return { pointeurs, noms }
}
CListeObjets.prototype.detruitDernierObjet = function () {
const ind = this.longueur() - 1
if (ind >= 0) {
this.remove(ind)
}
}
/**
* Fonction retirant l'objet el de la liste
* @param el
*/
CListeObjets.prototype.removeObject = function (el) {
const ind = this.indexOf(el)
if (ind !== -1) this.col.splice(ind, 1)
}
CListeObjets.prototype.removeByInd = function (ind) {
this.col.splice(ind, 1)
}
/**
* Fonction retirant l'objet el de la liste sans utiliser this.get
* Utilisé dans la reclassement d'objet
* @param el
*/
/*
Version 6.8.0 : Cette fonction était redéfinie dans CListeObjetsAddPlus donc à priori pas utilisée
Je la supprime donc, la retire de CListeObjetsAddPLus et met la définition ici
CListeObjets.prototype.removeObj = function (el) {
for (let i = 0; i < this.longueur(); i++) {
if (this.col[i] === el) this.col.splice(i, 1)
}
}
*/
/**
* Fonction retirant de la liste l'objet obj
* @param obj
*/
CListeObjets.prototype.removeObj = function (obj) {
const ind = this.indexOf(obj)
// Version 6.8.0 : Cette fonction étant appelée lors du reclassement d'objet ou dans OutilFinirConst
// pour des objets sans composant associé, on ne détruit pas le composant associé car l'élément va ^tre déplacé et non détruit
// if (ind !== -1) this.remove(this.indexOf(obj))
if (ind !== -1) this.remove(this.indexOf(obj), false)
}
/**
* Fonction retirant de la liste l'objet el
* @param el
*/
CListeObjets.prototype.detruitObjet = function (el) {
const ind = this.indexOf(el)
if (ind >= 0) {
this.remove(ind)
}
}
/**
* Fonction insérant l'objet el à l'index index
* A noter qu'après appel à cette fontion il faut appeler updateindexes
* @param index
* @param elb
*/
CListeObjets.prototype.insert = function (index, elb) {
if (elb.estDeNatureCalcul(NatCal.NMesureLongueur) && (this.pointeurLongueurUnite === null)) this.pointeurLongueurUnite = elb
this.col.splice(index, 0, elb)
}
/**
* Procedure utilisée lors de la création de la liaison entre un point libre
* et un objet dans le cas où le point libre a été créé avant l'objet. Il faut
* alors décaler (du dernier au premier) tous les objets créés entre le point
* libre d'indice IndObj1 et l'objet d'indice indObj2 auquel il faut le lier
*/
CListeObjets.prototype.decaleDependants = function (indObj1, indObj2) {
let indiceObjet2, indiceDebut, imp, nb
const el2 = this.get(indObj2)
if (el2.estElementFinal) {
indiceDebut = this.indexOf(el2.impProto) - 1
indiceObjet2 = this.indexOf(el2.impProto.dernierObjetFinal())
} else {
indiceDebut = indObj2 - 1
indiceObjet2 = indObj2
}
const objet1 = this.get(indObj1)
let i = indiceDebut
while (i >= indObj1) {
const element = this.get(i)
if (element.appartientABlocDependantPourReclassement(objet1)) {
if (indiceObjet2 === this.longueur() - 1) this.add(element)
else this.insert(indiceObjet2 + 1, element)
this.removeByInd(i)
indiceObjet2--
i--
// Si l'objet qu'on vient de reclasser est le dernier objet final d'une
// implémentation de construction
// il aut recoller lo corps de la construction avec lui
if (element.estElementFinal) {
imp = element.impProto
nb = imp.nbFinaux + imp.nbIntermediaires
for (let k = 0; k < nb; k++) {
const el1 = this.get(i)
this.insert(indiceObjet2 + 1, el1)
this.removeByInd(i)
indiceObjet2--
i--
}
}
} else {
if (element.estElementFinal) {
// Il ne faut pas désolidariser le dernier élément final de son
// implémentation de prototype
imp = element.impProto
nb = imp.nbFinaux + imp.nbIntermediaires + 1
i -= nb
} else { i-- }
}
}
// Ajout version 4.8.0
this.updateIndexes()
//
}
/**
* Fonction recherchant si la liste contient une transformation équivalente à la transformation trans
* Si oui renvoie un pointeur sur cette transformation
* Si non, renvoir null
* @param trans
*/
CListeObjets.prototype.transformationConfondueAvec = function (trans) {
for (const elb of this.col) {
if (elb.estDeNature(NatObj.NTransformation)) {
if (elb.confonduAvec(trans)) return elb
}
}
return null
}
/**
* Fonction ajoutant à this les objets graphiques de list qui sont de nature nature, sont visibles, ne sont pas des objets
* intermédiaitres de construction et qui dépendent de el
* @param {CListeObjets} list
* @param {NatObj} nature
* @param el L'objet dont les objets ajoutés doivent dépendre
* @param {boolean} bOnlySurfLieuObj si true, pour les surfaces, ne les rajoute que si elles peuvent générer un lieu d'objets
* @returns {void}
*/
CListeObjets.prototype.ajouteObjetsParNatureDependantDe = function (list, nature, el, bOnlySurfLieuObj) {
for (const elb of list.col) {
let elbok = elb.estDeNature(nature) && !elb.masque && !elb.estElementIntermediaire() && elb.depDe(el)
if (bOnlySurfLieuObj) elbok = elbok && (!elb.estDeNature(NatObj.NSurface) || elb.peutGenererLieuObjet())
if (elbok) this.add(elb)
}
}
CListeObjets.prototype.metAJourParNatureObjet = function (nat) {
for (const elb of this.col) {
if (elb.estDeNature(nat)) elb.metAJour()
}
}
/**
* Fonction renvoyant true si la liste contient au moins un objet qui dépend
* des positions générées pas les déplacements du point lié point lié
*
* @param pointLie
* @returns {boolean}
*/
CListeObjets.prototype.contientObjetGenereParPointLie = function (pointLie) {
for (const elb of this.col) {
if (elb.estGenereParPointLie(pointLie)) return true
}
return false
}
/**
* Fonction ajoutant à this les éléments de list de nature graphique nature qui ne sont pas masqués
* @param {CListeObjets} list
* @param {Nat} nature
* @returns {void}
*/
CListeObjets.prototype.ajouteObjetsParNatureNonMasques = function (list, nature) {
for (const el of list.col) {
if (!el.masque && el.estDeNature(nature)) this.add(el)
}
}
/**
* Fonction renvoyant un pointeur sur la valeur réelle ou complexe de nom nomValeur.
* Si indiceMaxi vaut -1 ou est absent la recherche se fait jusqu'à la fin de la liste.
* Les éléments intermédiares de construction sont sautés.
* Sinon, si l'élément est trouév mais son indice supérieur à indiceMaix,
* definiApres.getValue() renvoie true.
* Si l'élément n'est pas trouvé, rencovie null.
* @param {string} nomValeur
* @param {number} indiceMaxi
* @param {Pointeur} definiApres
* @returns {CElementBase}
*/
CListeObjets.prototype.pointeurValeurReelleOuComplexe = function (nomValeur, indiceMaxi, definiApres) {
let defap
if (arguments.length <= 2) defap = new Pointeur()
else defap = definiApres
if (arguments.length === 1) indiceMaxi = this.longueur() - 1
else if (indiceMaxi === -1) indiceMaxi = this.col.longueur() - 1
defap.setValue(false)
let i = 0
let elb = null
let trouve = false
while ((!(trouve)) && (i <= indiceMaxi)) {
elb = this.get(i)
if (!elb.estElementIntermediaire() && elb.estDeNatureCalcul(NatCal.NTteValROuC)) {
if (elb.chaineEgaleANom(nomValeur)) trouve = true
else i++
} else i++
}
if (trouve) return elb
else {
i = indiceMaxi + 1
while (!trouve && (i < this.longueur())) {
elb = this.get(i)
if (elb.estDeNatureCalcul(NatCal.NTteValROuC)) {
if (elb.chaineEgaleANom(nomValeur)) trouve = true
else i++
} else i++
}
if (trouve) defap.setValue(true)
return null
}
}
/**
* Fonction renvoyant le nombre d'objets de la liste dépendant de pt
* @param {CElementBase} pt
* @returns {number}
*/
CListeObjets.prototype.nombreDependants = function (pt) {
let res = 0
for (const el of this.col) {
if (el.depDe(pt)) res++
}
return res
}
/**
* Retire de la liste les n derniers éléments.
* @param {number} n (entier)
* @returns {void}
*/
CListeObjets.prototype.retireNDerniersElements = function (n) {
for (let i = 0; i < n; i++) this.col.pop()
}
/**
* Fonction renvoyant le nombre d'objets de type calcul compatible avec nat
* @param nat La nature de calcul recherchée
* @param binterm Si true on recherche aussi dans les objets intermédiaires de construction. false si paramètre absent.
* @returns {number}
*/
CListeObjets.prototype.nombreObjetsCalcul = function (nat, binterm = false) {
let nb = 0
for (const el of this.col) {
if (el.estDeNatureCalcul(nat) && (binterm || !el.estElementIntermediaire())) nb++
}
return nb
}
CListeObjets.prototype.utiliseLongueurUnite = function () {
for (const el of this.col) {
if (el.utiliseLongueurUnite()) return true
}
return false
}
/**
* Fonction renvoyant un pointeur vers le premier objet de classe className qui soit confondu avec obj
* Renvoie null si aucun élément n'est trouvé
* @param {string} className
* @param {CElementBase} obj
* @returns {CElementBase|null}
*/
CListeObjets.confonduAvec = function (className, obj) {
for (const el of this.col) {
if (!el.estElementIntermediaire() && (el.className === className) && el.confonduAvec(obj)) return el
}
return null
}
/**
* Fonction renvoyant null si la liste ne contient pas de point image de pt
* par la transformation transf et sinon un pointeur sur ce point image.
* @param {CPt} pt
* @param {CTransformation} transf
* @returns {CPointImage}
*/
CListeObjets.prototype.pointImageDePar = function (pt, transf) {
for (const elb of this.col) {
if (elb.estDeNature(NatObj.NPoint)) {
if (elb.estPointImage()) {
if ((elb.transformation === transf) && (elb.antecedent === pt)) return elb
}
}
}
return null
}
/**
* Fonction renvoyant le premier élémnet graphique après l'élément d'indice ind
* Si aucun objet graphique n'est trouvé, renvoie null
* @param ind
* @returns {COb|null}
*/
CListeObjets.prototype.getFirstGraphicEltAfter = function (ind) {
for (let i = ind + 1; i < this.longueur(); i++) {
const el2 = this.get(i)
if (el2.estDeNature(NatObj.NTtObj) && el2.g !== null) return el2
}
return null
}
/**
* Fonction insérant dans la liste l'objet el à l'indice el
* Si le paramètre svg n'est pas null, on retire du svg le svg element de el pour le remettre
* au bon endroit
* @param {CElementBase} el
* @param {number} indice
* @param {SVGElement|null} svg
*/
CListeObjets.prototype.insereElement = function (el, indice, svg = null) {
this.col.splice(indice, 0, el)
if (svg && el.estDeNature(NatObj.NTtObj) && el.g !== null) {
const nextelt = this.getFirstGraphicEltAfter(indice)
if (nextelt !== null) {
svg.removeChild(el.g)
svg.insertBefore(el.g, nextelt.g)
}
}
}
CListeObjets.prototype.removegElements = function (svg, bMemeInterm = false, indStart = 0, indMax = null) {
const indFin = (indMax === null) ? this.longueur() - 1 : indMax
for (let i = indStart; i <= indFin; i++) {
const el = this.get(i)
try {
if ((!el.estElementIntermediaire() || bMemeInterm) && el.estDeNature(NatObj.NTtObj)) {
svg.removeChild(el.g)
el.g = null
if ((el.estDeNature(NatObj.NObjNommable) || (el.estDeNature(NatObj.NObjetDuplique))) && (el.gname !== null)) {
svg.removeChild(el.gname)
el.gname = null
} else if (el.estDeNature(NatObj.NEditeurFormule) && !el.masque && el.affichageFormule && el.glatex) {
// Pour les éditeurs de formules avec affichage de la formule il faut aussi retirer l'affichage LaTeX correspondant
svg.removeChild(el.glatex)
}
}
} catch (e) {
el.g = null
if ((el.estDeNature(NatObj.NObjNommable) || (el.estDeNature(NatObj.NObjetDuplique))) && (el.gname !== null)) el.gname = null
}
}
}
CListeObjets.prototype.nombreImagesParTransformation = function (transf) {
const ind = transf.index
let res = 0
for (let i = ind + 1; i < this.longueur(); i++) {
const elb = this.get(i)
const elb2 = elb.antecedentDirect()
if ((elb2 !== elb) && (elb2 === transf)) res++
}
return res
}
/**
* Fonctions envoyant le nombre d'imagespar la tansformation transf autres que exclu
* @param transf
* @param exclu
* @returns {number}
*/
CListeObjets.prototype.nombreImagesParTransformationNonDepDe = function (transf, exclu) {
// var ind = indexOf(transf);
const ind = transf.index
let res = 0
for (let i = ind + 1; i < this.longueur(); i++) {
const elb = this.get(i)
if (!elb.depDe(exclu)) {
const elb2 = elb.antecedentDirect()
// if ((elb2 != elb) && (elb2.getNature() == NatObj.NTransformation) && (elb2 == transf))
if ((elb2 !== elb) && (elb2 === transf)) res++
}
}
return res
}
/**
* Fonction retirant de la liste les objets qui dépendent de pt
* Nommée retireDependants dans la version Java
* @param {CElementBase} pt
* @param svg Le svg contenant la figure
* @param {boolean} bRemovegElements Si true en retire du SVG les g Elements de chaque objet détruit
* Ce paramètre sera false quand on détruit un objet dans l'historique
* @returns {void}
*/
CListeObjets.prototype.detruitDependants = function (pt, svg, bRemovegElements = true) {
// Ajout version 3.4.2
this.initialiseDependances()
let existeImplementationsProtoATraiter = false
let index = this.col.length - 1
while (index >= 0) {
const elb = this.get(index)
if (elb.depDe(pt) || ((elb.impProto !== null) && elb.impProto.depDe(pt))) {
if (elb === this.pointeurLongueurUnite) this.pointeurLongueurUnite = null
const impProto = elb.impProto
if (impProto !== null) {
existeImplementationsProtoATraiter = true
if (elb.estElementFinal) {
impProto.nbFinaux--
} else {
impProto.nbIntermediaires--
}
}
// Ligne suivante modifié pour simplification
// this.remove(elb.index); // Attention : ce remove(CObject obj) est redéfini pour détruire aussi le composant MtgFormulaEditor
this.remove(index) // Attention : ce remove(CObject obj) est redéfini pour détruire aussi le composant MtgFormulaEditor
if (bRemovegElements && elb.estDeNature(NatObj.NTtObj)) {
addQueue(function () {
elb.removegElement(svg)
})
} // On retire le gElement qui représente l'objet
// associé à un CEditeurFormule
}
if (elb === pt) break
index--
}
if (existeImplementationsProtoATraiter) this.traiteImplementationsProto()
this.updateIndexes()
}
/**
* Fonction retirant de la liste les CImplementationProto qui sont orphelines (tous
* les éléments finaux de la construction ont été détruits) ou retirant de ces CImplementationProto
* les objets intermédiaires de fin qui ne sont plus utiles (arrive quand l'utilisateur a supprimé
* certains objets finaux.
* @returns {void}
*/
CListeObjets.prototype.traiteImplementationsProto = function () {
// for (var i = 0; i < this.longueur(); i++) {
let i = 0; let j
while (i < this.longueur()) {
const elb = this.get(i)
if (elb.estDeNature(NatObj.NImpProto)) {
if (elb.nbFinaux === 0) {
// this.detruitDependants(elb, svg);
// i = 0; // On recommence depuis le début
for (j = 0; j <= elb.nbIntermediaires; j++) this.remove(i)
} else {
const deb = i + elb.nbFinaux + elb.nbIntermediaires
// Attention : quand on exécute certaines macros d'implémentatio récursive de macro
// on peut demander de ne créer que les objets finaux de dernière génération
// dans ce cas le nombbre réel d'objets finaux n'est pas elb.nbFinaux
// Pour éviter d'y toucher il faut vérifier que l'élement d'indice deb
// appartient bien à l'impémentation proto elb
const lastelt = this.get(deb)
if (lastelt.impProto === elb && lastelt.estElementIntermediaire()) {
// Si le dernier élément d'une CImplémentationProto est un objet intermédiaire
// Il faut détruire tous les objets intermédiaires finaux.
for (j = deb; j > i; j--) {
if (this.get(j).estElementIntermediaire()) {
this.remove(j)
elb.nbIntermediaires--
} else break
}
}
i += elb.nbFinaux + elb.nbIntermediaires + 1
}
} else i++
}
}
/**
* Fonction renvoyant le premier objet de la liste qui existe (si bMustExist = true) et qui est un repère
* qui n'est pas un objet intermédiaire de construction.
* @param {boolean} bMustExist Si true le repère doit exister, sinon il peut ne pas exister (utiliser pour la création
* d'une figure avec papier millimétré)
* @returns {CElementBase|null}
*/
CListeObjets.prototype.premierRepVis = function (bMustExist = true) {
for (const elb of this.col) {
if ((elb.getNatureCalcul() === NatCal.NRepere) && (bMustExist ? elb.existe : true) && !elb.estElementIntermediaire()) return elb
}
return null
}
CListeObjets.prototype.ajouteRepereOrthonormal = function (dimf, quadrillageHor,
quadrillageVer, pointille, nomO, nomI, nomJ, nomVecteuri,
nomVecteurj, originex, originey, unitex, unitey, nomsIJmasques) {
// var stfp = StyleTrait.stfp(this);
const stfc = StyleTrait.stfc(this)
const petitRond = MotifPoint.petitRond
const res = dimf.y / 20 // Arbitraire version js
const absnom = CDroite.abscisseNomParDefaut
const bl = Color.black
// res contient la résolution de l'écran en points par cm
const o = new CPointBase(this, null, false, bl, false, -12, 0, false, nomO, 14, petitRond,
false, false, dimf.x / 2, dimf.y / 2)
this.add(o)
// Ensuite une droite horizontale passant par ce point cachée
const ptdh = new CDroiteDirectionFixe(this, null, false, bl, false, 0, 0, true, '', 14, stfc,
absnom, o, true, 1)
this.add(ptdh)
// On ajoute un point nommé lié à la droite horizontale
const i = new CPointLieDroite(this, null, false, bl, nomsIJmasques, -6, 0, false, nomI, 14, petitRond,
false, false, res, ptdh)
this.add(i)
// Une droite représentant l'axe des abscisses.
const ptd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 16, stfc, absnom, o, i)
this.add(ptd)
// On crée une perpendiculaire
const perp = new CDroitePerpendiculaire(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, ptd)
this.add(perp)
// On crée un cercle de centre O et passant par I
const cercle = new CCercleOA(this, null, false, bl, true, stfc, o, i)
this.add(cercle)
// On crée l'intersection de ce cercle avec la perpendiculaire
const inter = new CIntDroiteCercle(this, null, false, perp, cercle)
this.add(inter)
// Puis deux points représentant les deux points d'intersection
// Le premier point est caché sans nom
const k = new CPointLieBipoint(this, null, false, bl, false, 0, 0, true, '', 14,
petitRond, false, inter, 1)
this.add(k)
const j = new CPointLieBipoint(this, null, false, bl, nomsIJmasques, -12, -4, false, nomJ, 14,
petitRond, false, inter, 2)
this.add(j)
// puis le repère
this.finitRep(o, i, j, nomVecteuri, nomVecteurj, originex, originey, quadrillageVer, quadrillageHor,
pointille, unitex, unitey)
}
CListeObjets.prototype.ajouteRepereOrthogonal = function (dimf, quadrillageHor,
quadrillageVer, pointille, nomO, nomI, nomJ, nomVecteuri,
nomVecteurj, originex, originey, unitex, unitey, nomsIJmasques) {
// var stfp = StyleTrait.stfp(this);
const stfc = StyleTrait.stfc(this)
const petitRond = MotifPoint.petitRond
const resx = dimf.x / 20 // Arbitraire version js
const resy = dimf.y / 15 // Arbitraire version js
const absnom = CDroite.abscisseNomParDefaut
const bl = Color.black
// res contient la résolution de l'écran en points par cm
const o = new CPointBase(this, null, false, bl, false, -12, 0, false, nomO, 14, petitRond,
false, false, dimf.x / 2, dimf.y / 2)
this.add(o)
// Ensuite une droite horizontale passant par ce point cachée
const ptdh = new CDroiteDirectionFixe(this, null, false, bl, false, 0, 0, true, '', 14, stfc,
absnom, o, true, 1)
this.add(ptdh)
// On ajoute un point nommé lié à la droite horizontale
const i = new CPointLieDroite(this, null, false, bl, nomsIJmasques, -6, 0, false, nomI, 14, petitRond,
false, false, resx, ptdh)
this.add(i)
// Une droite représentant l'axe des abscisses.
const ptd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, i)
this.add(ptd)
// On crée une perpendiculaire
const perp = new CDroitePerpendiculaire(this, null, false, bl, false, 0, 0, true, '', 14, stfc, absnom, o, ptdh)
this.add(perp)
const j = new CPointLieDroite(this, null, false, bl, nomsIJmasques, -11, 0, false, nomJ, 14, petitRond,
false, false, -resy, perp)
// this, null, false, bl, false, -11, 0, false, "", 14, stfc, false, true, absnom, perp)
this.add(j)
const axeOrd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, j)
this.add(axeOrd)
// puis le repère
this.finitRep(o, i, j, nomVecteuri, nomVecteurj, originex, originey, quadrillageVer, quadrillageHor,
pointille, unitex, unitey)
}
CListeObjets.prototype.ajouteRepereOblique = function (dimf, quadrillageHor,
quadrillageVer, pointille, nomO, nomI, nomJ, nomVecteuri,
nomVecteurj, originex, originey, unitex, unitey, nomsIJmasques) {
// var stfp = StyleTrait.stfp(this);
const stfc = StyleTrait.stfc(this)
const petitRond = MotifPoint.petitRond
const resx = dimf.x / 20 // Arbitraire version js
const resy = dimf.y / 15 // Arbitraire version js
const absnom = CDroite.abscisseNomParDefaut
const bl = Color.black
// res contient la résolution de l'écran en points par cm
const o = new CPointBase(this, null, false, bl, false, -17, 0, false, nomO, 14, petitRond,
false, false, dimf.x / 2, dimf.y / 2)
this.add(o)
// Ensuite une droite horizontale passant par ce point cachée
const ptdh = new CDroiteDirectionFixe(this, null, false, bl, false, 0, 0, true, '', 14, stfc,
absnom, o, true, 1)
this.add(ptdh)
// On ajoute un point nommé lié à la droite horizontale
const i = new CPointLieDroite(this, null, false, bl, nomsIJmasques, -10, 0, false, nomI, 14, petitRond,
false, false, resx, ptdh)
this.add(i)
// Une droite représentant l'axe des abscisses.
const ptd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, i)
this.add(ptd)
const j = new CPointBase(this, null, false, bl, nomsIJmasques, -11, -4, false, nomJ, 14, petitRond,
false, false, dimf.x / 2 + resx / 4, dimf.y / 2 - resy / 2)
this.add(j)
const axeOrd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, j)
this.add(axeOrd)
// puis le repère
this.finitRep(o, i, j, nomVecteuri, nomVecteurj, originex, originey, quadrillageVer, quadrillageHor,
pointille, unitex, unitey)
}
CListeObjets.prototype.ajouteRepereObliqueNorme = function (dimf, quadrillageHor,
quadrillageVer, pointille, nomO, nomI, nomJ, nomVecteuri,
nomVecteurj, originex, originey, unitex, unitey, nomsIJmasques) {
// var stfp = StyleTrait.stfp(this);
const stfc = StyleTrait.stfc(this)
const petitRond = MotifPoint.petitRond
const resx = dimf.x / 20 // Arbitraire version js
const absnom = CDroite.abscisseNomParDefaut
const bl = Color.black
// res contient la résolution de l'écran en points par cm
const o = new CPointBase(this, null, false, bl, false, -17, 0, false, nomO, 14, petitRond,
false, false, dimf.x / 2, dimf.y / 2)
this.add(o)
// Ensuite une droite horizontale passant par ce point cachée
const ptdh = new CDroiteDirectionFixe(this, null, false, bl, false, 0, 0, true, '', 14, stfc,
absnom, o, true, 1)
this.add(ptdh)
// On ajoute un point nommé lié à la droite horizontale
const i = new CPointLieDroite(this, null, false, bl, nomsIJmasques, -10, 0, false, nomI, 14, petitRond,
false, false, resx, ptdh)
this.add(i)
// Une droite représentant l'axe des abscisses.
const ptd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, i)
this.add(ptd)
ptd.tag = 'xaxis'
// On crée un cercle de centre O et passant par I
const cercle = new CCercleOA(this, null, false, bl, true, stfc, o, i)
this.add(cercle)
const j = new CPointLieCercle(this, null, false, bl, nomsIJmasques, -12, 0, false, nomJ, 14, MotifPoint.petitRond, false, false, Math.PI / 3, cercle)
this.add(j)
const axeOrd = new CDroiteAB(this, null, false, bl, false, 0, 0, false, '', 14, stfc, absnom, o, j)
this.add(axeOrd)
axeOrd.tag = 'yaxis'
// puis le repère
this.finitRep(o, i, j, nomVecteuri, nomVecteurj, originex, originey, quadrillageVer, quadrillageHor,
pointille, unitex, unitey)
}
/**
* Fonction finissnat la création d'un repère ajouté à une nnouvelle figure
* @param o L'origine
* @param i Le point de coordonnées (1;0)
* @param j Le point de coordonnées (1;0)
* @param nomVecteuri Le nom du vecteur i ("" si pas de vecteur)
* @param nomVecteurj Le nom du vecteur j ("" si pas de vecteur)
* @param originex L'abscisse à l'origine
* @param originey L'ordonnée à l'origine
* @param quadrillageVer true si quadriallage vertical
* @param quadrillageHor true si quadrillage horizontal
* @param pointille true si pointillés
* @param unitex L'unité sur l'axe des x
* @param unitey L'unité sur l'axe des y
*/
CListeObjets.prototype.finitRep = function (o, i, j, nomVecteuri, nomVecteurj, originex, originey,
quadrillageVer, quadrillageHor, pointille, unitex, unitey) {
const bl = Color.black
// var stfp = StyleTrait.stfp(this);
const stfc = StyleTrait.stfc(this)
const rep = new CRepere(this, null, false, (pointille && !quadrillageHor && !quadrillageVer)
? new Color(164, 164, 164)
: new Color(230, 230, 230), false, stfc, o, i, j, originex, originey, quadrillageVer, quadrillageHor, pointille, unitex, unitey)
this.add(rep)
// On donne par défaut au repère le tag rep pour qu'on puisse utiliser les apiTools dessus
rep.tag = 'rep'
// On crée la longueur OI qu'on établit comme longueur nité de la liste
// this, null, false, O, I);
const unitexrep = new CUnitexRep(this, null, false, 'unit', rep)
this.add(unitexrep)
const hom = new CHomothetie(this, null, false, o, new CValeur(this, new COperation(this, new CConstante(this, 1),
new CResultatValeur(this, unitexrep), Ope.Divi)))
this.add(hom)
const ptim = new CPointImage(this, null, false, bl, false, 0, 0, true, 'W"', 16, MotifPoint.rond, false, i, hom)
this.add(ptim)
const lon = new CLongueur(this, null, false, o, ptim)
this.pointeurLongueurUnite = lon
this.add(lon)
if (nomVecteuri.length !== 0) {
const vecti = new CVecteur(this, null, false, bl, false, stfc, o, i, StyleFleche.FlecheCourtePleine)
this.add(vecti)
const commi = new CLatex(this, null, false, bl, 0, 0, -10, 2, false, i, 16, StyleEncadrement.Sans, false,
Color.white, CAffLiePt.alignHorRight,
CAffLiePt.alignVerTop, '\\vec{' + nomVecteuri + '}')
// commi.creeFormule();
// commi.setReady4MathJax();
this.add(commi)
}
if (nomVecteurj.length !== 0) {
const vectj = new CVecteur(this, null, false, bl, false, stfc, o, j, StyleFleche.FlecheCourtePleine)
this.add(vectj)
const commj = new CLatex(this, null, false, bl, 0, 0, -8, 5, false, j, 16, StyleEncadrement.Sans, false,
Color.white, CAffLiePt.alignHorRight,
CAffLiePt.alignVerTop, '\\vec{' + nomVecteurj + '}')
// commj.creeFormule();
// commj.setReady4MathJax();
this.add(commj)
}
}
/**
* Fonction renvoyant le premier objet de nature calcul nat qui n'est pas un objet intermédiaire de construciton
* @param {Nat} nat
* @returns {CElementBase|null}
*/
CListeObjets.prototype.premierParNatCal = function (nat) {
for (const elb of this.col) {
if ((elb.estDeNatureCalcul(nat)) && !elb.estElementIntermediaire()) return elb
}
return null
}
/**
* Fonction renvoyant l'objet d'indice index (l'objet n° index - 1) de nature nat
* @param {Nat} nat
* @param {number} index
* @param {boolean} bInterm Si true on cherche aussi dans les objets intermédiaires de construction
* @returns {CElementBase|null}
*/
CListeObjets.prototype.premierParNat = function (nat, index = 0, bInterm = false) {
let ind = 0
for (const elb of this.col) {
if ((elb.estDeNature(nat)) && (bInterm || !elb.estElementIntermediaire())) {
if (ind === index) return elb
else ind++
}
}
return null
}
// Modifié version 6.8.0
CListeObjets.prototype.ajouteConstantePi = function () {
const ptCalc = new CCalcConst(this, null, false, 'pi', '3.14159265358979323846', new CConstante(this, Math.PI))
this.add(ptCalc)
}
/**
* Renvoie true si la liste contient un point dont les coordonnées sont
* "presque" égales à x et y et qui soit sur les el1 et el2
* Dans la version JavaScript el1 et el2 peuvent pointer indifféremmen sur une droite ou un cercle
* Si oui renvoit un pointeur sur ce point, sinon renvoie null
* @param {number} x
* @param {number} y
* @param {CElementBase} el1
* @param {CElementBase} el2
* @param {boolean} bEstExercice true si on est en mode exercice de construction Dans ce cas on n'utilise pas de technique intelligente
* d'appartenance à el1 et el2 et on considère que le point existe déjà s'il est très proche d'un point déjà créé.
* @returns {CElementBase|null}
*/
CListeObjets.prototype.existePointConfonduPourIntersection = function (x, y, el1, el2, bEstExercice) {
for (let i = 0; i < this.longueur(); i++) {
const elb = this.get(i)
if (elb.estDeNature(NatObj.NTtPoint)) {
// Modification version 3.9 : Si l'intersection a déjà été créée pour un objet intermédiaire de construction
// on crée de nouveau l'objet
if (!elb.estElementIntermediaire() && elb.existe) {
const presqueEgaux = zero(elb.x - x) && zero(elb.y - y)
if (bEstExercice) {
if (presqueEgaux) return elb
} else {
if (presqueEgaux && elb.appartientParDefinition(el1) && elb.appartientParDefinition(el2)) {
return elb
}
}
}
}
}
return null
}
/**
* Etudie l'intersection de el1 et el2 a déjà été créé.
* si el1 et el2 sont deux droites, renvoie true si le point d'intersection
* existe déjà dans la figure.
* S'il s'agit d'une droite et un cercle ou de deux cercles, dejaCree.getValue()
* renvoie true quand les deux points d'intersection ont déjà été créés et false sinon.
* et si un des deux points d'intersection a déjà été créé, renvoie un
* pointeur sur ce point. Sinon renvoit null.
* @param {boolean} bEstExercice true si on est en mode exercice de construction
* @param {CElementGraphique} el1 droite ou cercle
* @param {CElementGraphique} el2 droite ou cercle
* @param {Pointeur} dejaCree Renvoie true quand les deux points d'intersection
* ont déjà été créés et false sinon.
* @returns {CPt}
*/
CListeObjets.prototype.pointIntersectionDejaCree = function (bEstExercice, el1, el2, dejaCree) {
let positionRelative, pointInt2, ptPoint1, ptPoint2
const pointInt1 = {}
if (arguments.length === 3) { // : Cas de deux droites. Renvoie un booléen}
positionRelative = intersection(el1.point_x, el1.point_y, el1.vect, el2.point_x,
el2.point_y, el2.vect, pointInt1)
if (positionRelative !== PositionDroites.Paralleles) { return this.existePointConfonduPourIntersection(pointInt1.x, pointInt1.y, el1, el2, bEstExercice) } else return null
} else {
if (el1.estDeNature(NatObj.NTteDroite) && el2.estDeNature(NatObj.NTtCercle)) {
pointInt2 = {}
dejaCree.setValue(false)
positionRelative = intersectionDroiteCercle(el1.point_x, el1.point_y, el1.vect,
el2.centreX, el2.centreY, el2.rayon, pointInt1, pointInt2)
ptPoint1 = this.existePointConfonduPourIntersection(pointInt1.x, pointInt1.y, el1, el2, bEstExercice)
ptPoint2 = this.existePointConfonduPourIntersection(pointInt2.x, pointInt2.y, el1, el2, bEstExercice)
if (positionRelative === PositionDroiteCercle.Secants) {
dejaCree.setValue((ptPoint1 !== null) && (ptPoint2 !== null))
if (dejaCree.getValue()) return null
else {
if (ptPoint1 !== null) return ptPoint1
else {
if (ptPoint2 !== null) return ptPoint2
else return null
}
}
} else {
if (positionRelative === PositionDroiteCercle.Tangents) {
dejaCree.setValue(ptPoint1 !== null)
if (dejaCree.getValue()) return ptPoint1
else return null
} else return null
}
} else { // Cas de deux cercles
pointInt2 = { x: 0, y: 0 }
dejaCree.setValue(false)
positionRelative = intersectionCercleCercle(el1.centreX, el1.centreY, el1.rayon,
el2.centreX, el2.centreY, el2.rayon, pointInt1, pointInt2)
ptPoint1 = this.existePointConfonduPourIntersection(pointInt1.x, pointInt1.y, el1, el2, bEstExercice)
ptPoint2 = this.existePointConfonduPourIntersection(pointInt2.x, pointInt2.y, el1, el2, bEstExercice)
if (positionRelative === PositionCercleCercle.Secants) {
dejaCree.setValue((ptPoint1 !== null) && (ptPoint2 !== null))
if (dejaCree.getValue()) return null
else {
if (ptPoint1 !== null) return ptPoint1
else {
if (ptPoint2 !== null) return ptPoint2
else return null
}
}
} else {
if (positionRelative === PositionCercleCercle.Tangents) {
dejaCree.setValue(ptPoint1 !== null)
if (dejaCree.getValue()) return ptPoint1
else return null
} else return null
}
}
}
}
CListeObjets.prototype.ajouteLongueurUnite = function (app) {
// On charge la construction qui est contenue dans this.app.docConst
const proto = app.docCons.getPrototype('LongUnit')
const impProto = new CImplementationProto(this, proto)
impProto.implemente(app.dimf, proto)
const pt1 = this.get(2) // Le point libre de gauche
pt1.tailleNom = 14
const pt2 = this.get(4) // Le point libre de gauche
pt2.tailleNom = 14
impProto.nomProto = getStr('LongUnite')
// La longueur unité est le dernier objet implémenté par la macro construction
this.pointeurLongueurUnite = this.get(this.longueur() - 1)
}
/**
* Fonction renvoyant un pointeur sur la droite passant par a et b si elle existe et null sinon
* @param {CPt} a
* @param {CPt} b
* @returns {CElementBase|null}
*/
CListeObjets.prototype.existeDroiteABDefiniePar = function (a, b) {
for (const el of this.col) {
if (el.className === 'CDroiteAB') {
if (((el.a === a) && (el.b === b)) || ((el.b === a) && (el.a === b))) return el
}
}
return null
}
/**
*
* @param {CElementBase} el
* @returns {boolean}
*/
CListeObjets.prototype.nomIndispensable = function (el) {
for (const elb of this.col) {
if (elb.nomIndispensable(el)) return true
}
return false
}
/**
*
* @param {Nat} typeCherche
* @param {number} x
* @param {number} y
* @param {string} type si touch on prend une distance de 32 (sinon 16)
* @param listeExclusion
* @returns {null|CElementBase}
*/
CListeObjets.prototype.premierObjetNomProcheDe = function (typeCherche, x, y, type, listeExclusion) {
// lorsque la liste est vide, aucun objet n'est proche
for (const el of this.col) {
if (el.estDeNature(typeCherche) && (listeExclusion.indexOf(el) === -1) && !(el.masque || el.nomMasque)) {
const dis = el.distanceNom(x, y, type === 'touch' ? 32 : 16)
if (dis === 0) return el // On est à l'intérieur de l'affichage du nom de l'objet
}
}
return null // Aucun nom d'objet proche
}
/**
* Fonction demandant à chaque objet pour lequel c'est nécéssaire de se préparer
* pour le traitement par MathJax qui sera fait via une fonction de callback.
* Appelée quand pn utilise l'outil Rideau.
* @returns {void}
*/
CListeObjets.prototype.setReady4MathJaxEvenMasked = function () {
for (const el of this.col) {
if (el.existe && !el.estElementIntermediaire()) el.setReady4MathJaxEvenMasked()
}
}
CListeObjets.prototype.updateEvenMasked = function (svg, couleurFond) {
this.setReady4MathJaxEvenMasked()
const self = this
for (const elb of this.col) {
addQueue(function () {
self.callBack(elb, svg, couleurFond, false)
})
}
}
/**
* Fonction ajoutant à this les points de la liste listeSource dont l'étatt de masquage est basque
* @param listeSource
* @param bmarque
*/
CListeObjets.prototype.ajoutePointsMarquesPourTrace = function (listeSource, bmarque) {
for (const elb of listeSource.col) {
if (elb.estDeNature(NatObj.NTtPoint) && !elb.estElementIntermediaire() && !elb.masque) {
if (elb.marquePourTrace === bmarque) this.add(elb)
}
}
}
CListeObjets.prototype.remplaceObjet = function (oldObj, newObj) {
const ind = this.indexOf(oldObj)
this.col[ind] = newObj
newObj.index = ind
}
/**
* Fonction ajoutant à this les points mobiles non intermédiaires dont l'état de liberté est égal à libres
* @param listeSource
* @param blibres
*/
CListeObjets.prototype.ajoutePointsLibresVisibles = function (listeSource, blibres) {
for (const elb of listeSource.col) {
if (elb.estDeNature(NatObj.NPointMobile) && !elb.estElementIntermediaire()) {
if (!elb.masque) {
if (elb.fixed !== blibres) { this.add(elb) }
}
}
}
}
/**
* Fonction ajoutant à this les objets de listeSource qui sont de nature graphique nat, qui sont visibles
* et dont le membre fixed est bFixed
* @param {CListeObjets} listeSource
* @param {Nat} nat
* @param {boolean} bFixed
*/
CListeObjets.prototype.addVisibleObjetsFixedOrNot = function (listeSource, nat, bFixed) {
for (const elb of listeSource.col) {
if (elb.estDeNature(nat) && !elb.estElementIntermediaire() && !elb.masque) {
if (elb.fixed === bFixed) { this.add(elb) }
}
}
}
/**
* Fonction renvoyant le nombre d'objets visibles de nature nat et dont la propriété fixed
* est égale à bFixed et qui ne sont pas masqués ou qui sont masqués si bEvenMasked est à true
* @param {Nat} nat
* @param {boolean} bFixed
* @param {boolean} bEvenMasked
* @returns {number}
*/
CListeObjets.prototype.nbVisibleObjectsFixedOrNot = function (nat, bFixed, bEvenMasked = false) {
let res = 0
for (const elb of this.col) {
if (elb.estDeNature(nat) && !elb.estElementIntermediaire() && (bEvenMasked || !elb.masque)) {
if (elb.fixed === bFixed) res++
}
}
return res
}
CListeObjets.prototype.ajoutePointsLiesVisiblesDontDepend = function (listeSource, elb) {
const indelb = listeSource.indexOf(elb)
for (let i = 0; i <= indelb; i++) {
const el = listeSource.get(i)
if (el.estDeNature(NatObj.NPointLie)) {
if (!el.masque && elb.depDe(el) && !this.contains(el)) this.add(el)
}
}
}
/**
* Fonction rajoutant à this les objets de list qui sont des affichages :
* liés à un point si blie ets true
* non liés à un point si blie est false
* @param {CListeObjets} list
* @param {boolean} blie
*/
CListeObjets.prototype.ajouteAffichagesLiesAPointVisibles = function (list, blie) {
for (const el of list.col) {
if (!el.estElementFinal && el.estDeNature(NatObj.NAffLieAPoint)) {
if (!el.masque && (blie ? (el.pointLie !== null) : (el.pointLie === null))) this.add(el)
}
}
}
/**
* Fonction ajoutant à this les points liés non punaisés contenus dans list
* @param {CListeObjets} list
*/
CListeObjets.prototype.ajoutePointsLiesNonPun = function (list) {
for (const el of list.col) {
if (el.estDeNature(NatObj.NPointLie)) {
if (!el.masque && !el.fixed) this.add(el)
}
}
}
/**
* Fonction retirant du body tous les div servant à modifier, incrémenter ou décrémenter une variable
*/
CListeObjets.prototype.removePaneVariables = function () {
for (let i = this.longueur() - 1; i >= 0; i--) {
const el = this.get(i)
// Lors des implémentations de proto il peut y avoir des variables ajoutées avec panneau associé
// mais pas encore créées, et dans ce cas el.div est undefined
const foreignElt = el.foreignElt
if (el.getNatureCalcul() === NatCal.NVariable && el.dialogueAssocie && foreignElt) {
foreignElt.parentNode.removeChild(foreignElt)
}
}
}
CListeObjets.prototype.metAJourSurfacesAyantPourBord = function (lieu) {
for (const el of this.col) {
if (el.estDeNature(NatObj.NSurface) && el.aPourBord(lieu)) el.metAJourTableaux()
}
}
/**
* Fonction renvoyant le nombre d'objet dont la nature graphique est une des natures
* contenues dans nat (par un et binaire). Les natures cherchées eoivent être graphiques.
* @param {Nat} nat
* @returns {number}
*/
CListeObjets.prototype.nombreObjetsParNatureVisibles = function (nat) {
let compt = 0
for (const elb of this.col) {
if (!elb.estElementIntermediaire() && elb.estDeNature(nat) && !elb.masque) compt++
}
return compt
}
/**
* Fonction renvoyant :
* Si blie est true le nombre d'affichages liés à un point visibles (non éléments finaux de construction
* Si blie est false, le nombre d'affichages non liés à un point visibles
* @param blie
* @returns {number}
*/
CListeObjets.prototype.nombreAffichagesLiesAPointVisibles = function (blie) {
let res = 0
for (const elb of this.col) {
if (!elb.estElementFinal && elb.estDeNature(NatObj.NAffLieAPoint)) {
if (!elb.masque && (blie ? elb.pointLie !== null : elb.pointLie === null)) res++
}
}
return res
}
/**
* Spécial version mtgApp
* Remplace dans les CCommentaire et CLatex utilisant des affichages dynamiques dépendant de el ancienNom par nouveauNom
* @param ancienNom
* @param nouveauNom
* @param el l'élément dont le commentaire ou le Clatex doit dépendre pour que le remplacement soit effectué
*/
CListeObjets.prototype.remplaceNomValeurDynamiqueDansCommentairesOuLatexDepDe = function (ancienNom, nouveauNom, el) {
for (const elb of this.col) {
if (elb.estDeNature(NatObj.NComouLatex) && elb.depDe(el)) elb.remplaceNomValeurDynamique(ancienNom, nouveauNom)
}
}
/**
* Fonction reconstruisant les chaînes de calcul de tous les calculs ou
* fonctions utilisateur dépendant de el.
* @returns {void}
*/
CListeObjets.prototype.reconstruitChainesCalculDepDe = function (el) {
for (const elb of this.col) {
if (elb.estDeNatureCalcul(NatCal.NCalcOuFoncNonConstante) && elb.depDe(el)) { elb.reconstruitChaineCalcul() }
}
}
/**
* Fonction renvoyant l'indice du premier objet qui ne soit pas une variable
* ou un calcul constant. Est utilisé pour le reclassement d'objets en début
* de liste
* @returns {number}
*/
CListeObjets.prototype.indicePremierElementNonVariable = function () {
let i
for (i = 0; i < this.longueur(); i++) {
const elb = this.get(i)
const nat = elb.getNatureCalcul()
if ((nat !== NatCal.NVariable) && (elb.className !== 'CCalcConst')) break
}
return i
}
/**
* Fonction reclassant au maximum l'objet elb vers le début de l liste des objets
* @param {CElementBase} elb l'objet à reclasser
* @param {SVGElement|null} svg Si svg n'est pas nul on reclasse aussi les SVG elements des objets
* @returns {boolean}
*/
CListeObjets.prototype.reclasseVersDebutAvecDependants = function (elb, svg = null) {
const indiceMiniDebut = this.indicePremierElementNonVariable()
const indiceItem = this.indexOf(elb)
if (indiceItem === indiceMiniDebut) return false
// On recherche à partir du début de la liste la position
// du premier item dont elb ne dépend pas
// On ne commence qu'au deuxième objet car le premier est la constante pi
let indiceMiniGauche = 1
let dependant = true
let i = indiceMiniDebut
while ((i <= indiceItem) && dependant) {
const el = this.get(i)
if (el.estDeNature(NatObj.NImpProto)) {
// CImplementationProto imp = (CImplementationProto) el;
dependant = elb.depDe4Rec(el)
const nb = el.nbFinaux + el.nbIntermediaires
if (dependant) i += nb + 1
else indiceMiniGauche = i
} else {
if (elb.depDe4Rec(el)) { i++ } else {
dependant = false
indiceMiniGauche = i
}
}
}
if (dependant) return false // elb qu'on veut reclasser dépend de tous les objets
// précédents
i = indiceMiniGauche + 1
while (i <= indiceItem) {
const el = this.get(i)
// Il ne faut pas séparer les éléments d'une implémentation de prototype
if (el.estDeNature(NatObj.NImpProto)) {
// CImplementationProto imp = (CImplementationProto) el;
const nb = el.nbFinaux + el.nbIntermediaires + 1
if (elb.depDe4Rec(el)) {
for (let k = 0; k < nb; k++) {
const el1 = this.get(i + k)
this.removeByInd(i + k)
this.insereElement(el1, indiceMiniGauche + k, svg)
}
indiceMiniGauche += nb
i += nb
} else {
i += nb
}
} else {
if (elb.depDe4Rec(el)) {
this.removeByInd(i)
this.insereElement(el, indiceMiniGauche, svg)
indiceMiniGauche++
}
i++
}
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction reclassant si c'est possible l'objet elb avant l'objet avant (ainsi que les objets dont dépend elb
* et situés entre avant et elb.
* @param {CElementBase} elb l'objet à reclasser
* @param avant l'objet avant lequel doit être reclassé elb
* @param {SVGElement|null} svg Si svg n'est pas nul on reclasse aussi les SVG elements des objets
* @returns {boolean} renvoie true si le reclassement a été possible et false sinon.
*/
CListeObjets.prototype.reclasseVersDebutAvant = function (elb, avant, svg = null) {
const indiceMiniDebut = this.indicePremierElementNonVariable()
const indiceItem = elb.index
// ON ne reclasse pas avant la dernière variable et elb doit être après avant
if (avant.index <= indiceMiniDebut || indiceItem <= avant.index) return false
// On recherche à partir du début de la liste la position
// du premier item dont elb ne dépend pas
// On ne commence qu'au deuxième objet car le premier est la constante pi
let indiceMiniGauche
if (avant.estElementFinal) {
// CImplementationProto imp = (CImplementationProto) el;
if (elb.appartientABlocDependantPourReclassement(avant)) return false
indiceMiniGauche = avant.impProto.index
} else {
if (elb.depDe4Rec(avant)) return false
indiceMiniGauche = avant.index
}
let i = indiceMiniGauche + 1
while (i <= indiceItem) {
const el = this.get(i)
// Il ne faut pas séparer les éléments d'une implémentation de prototype
if (el.estDeNature(NatObj.NImpProto)) {
// CImplementationProto imp = (CImplementationProto) el;
const nb = el.nbFinaux + el.nbIntermediaires + 1
if (elb.depDe4Rec(el)) {
for (let k = 0; k < nb; k++) {
const el1 = this.get(i + k)
this.removeByInd(i + k)
this.insereElement(el1, indiceMiniGauche + k, svg)
}
indiceMiniGauche += nb
i += nb
} else {
i += nb
}
} else {
if (elb.depDe4Rec(el)) {
this.removeByInd(i)
this.insereElement(el, indiceMiniGauche, svg)
indiceMiniGauche++
}
i++
}
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction décalant le plus possible vers la fin de la liste l'élément elb
* @param {CElementBase} elb
* @param {SVGElement|null} svg Si svg n'est pas nul on reclasse aussi les SVG elements des objets
* @returns {boolean} true si le décalage est possible et 0 sinon
*/
CListeObjets.prototype.reclasseVersFinAvecDependants = function (elb, svg = null) {
// Si l'élément à reclasser est un élément final d'une implémentation de
// prototype, c'est le dernier élément final
// qu'il faut reclasser vers la fin
let i, indexItem, indexFin, element, imp, nb
let indDebut = 0
if (elb.estElementFinal) {
indexItem = this.indexOf(elb.impProto)
indexFin = this.indexOf(elb.impProto.dernierObjetFinal())
} else {
indexItem = this.indexOf(elb)
indexFin = indexItem
}
if (indexFin === this.longueur() - 1) return false
// On recherche à partir de la fin de la liste la position
// du premier item qui ne dépende pas de elb
let indMaxiDroite = this.longueur() - 1
let dependant = true
for (i = this.longueur() - 1; (i !== indexFin) && dependant; i--) {
element = this.get(i)
if (element.estElementFinal) {
imp = element.impProto
if (!element.appartientABlocDependantPourReclassement(elb)) {
dependant = false
indDebut = i - imp.nbFinaux - imp.nbIntermediaires - 1
indMaxiDroite = i
}
// Modifié version 5.4 : Il ne faut pas soustraire 1 car cela va être fait en revenant au début de la boucle
// i = i - imp.nbFinaux - imp.nbIntermediaires - 1;
i = i - imp.nbFinaux - imp.nbIntermediaires
} else {
if (!element.dependDeBlocPourReclassement(elb)) {
dependant = false
indDebut = i - 1
indMaxiDroite = i
}
}
}
if (dependant) return false
// indMaxiDroite est l'indice du premier élément qui ne dépend pas de elb à
// partir de la fin de la liste
i = indDebut
while (i >= indexItem) {
element = this.get(i)
if (element.appartientABlocDependantPourReclassement(elb)) {
if (indMaxiDroite === this.longueur() - 1) this.add(element, svg)
else this.insereElement(element, indMaxiDroite + 1, svg)
this.removeByInd(i)
indMaxiDroite--
i--
// Si l'objet qu'on vient de reclasser est le dernier objet final d'une
// implémentation de construction
// il faut recoller le corps de la construction avec lui
if (element.estElementFinal) {
imp = element.impProto
nb = imp.nbFinaux + imp.nbIntermediaires
for (let k = 0; k < nb; k++) {
const el1 = this.get(i)
if (indMaxiDroite === this.longueur() - 1) this.add(el1, svg)
else this.insereElement(el1, indMaxiDroite + 1, svg)
this.removeByInd(i)
indMaxiDroite--
i--
}
}
} else {
if (element.estElementFinal) {
// Il ne faut pas désolidariser le dernier élément final de son
// implémentation de prototype
imp = element.impProto
nb = imp.nbFinaux + imp.nbIntermediaires + 1
i -= nb
} else { i-- }
}
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction reclassant l'objet elb après l'objet apres
* @param elb l'objet à reclasser ainsi que ceux qui en dépendent et situés avant apres
* @param apres l'objet après lequel il faut reclasser elb et ses dépendants
* @param {SVGElement|null} svg Si svg n'est pas nul on reclasse aussi les SVG elements des objets
* @returns {boolean} renvoie true si le reclassement a été possible et false sinon
*/
CListeObjets.prototype.reclasseVersFinApres = function (elb, apres, svg = null) {
// Si l'élément à reclasser est un élément final d'une implémentation de
// prototype, c'est le dernier élément final
// qu'il faut reclasser vers la fin
let indDebut
// Si les deux objets ne sont pas rangés dans le bon ordre ou sont deux objets
// finaux d'une même implémentation de construction c'est imopossible
if ((apres.index <= elb.index) || ((elb.impProto !== null) && (elb.impProto === apres.impProto))) return false
const indexItem = elb.estElementFinal ? elb.impProto.index : elb.index
// Si apres est un objet final de construction on reclasse après le dernier objet final de la construction
let indMaxiDroite
if (apres.estElementFinal) {
const imp = apres.impProto
if (apres.appartientABlocDependantPourReclassement(elb)) return false
else {
indDebut = imp.index - 1
// indMaxiDroite = imp.index + imp.nbFinaux + imp.nbIntermediaires
indMaxiDroite = imp.dernierObjetFinal().index
}
} else {
if (apres.dependDeBlocPourReclassement(elb)) return false
else {
indDebut = apres.index - 1
indMaxiDroite = apres.index
}
}
// indMaxiDroite est l'indice du premier élément qui ne dépend pas de elb à
// partir de la fin de la liste
let i = indDebut
while (i >= indexItem) {
const element = this.get(i)
if (element.appartientABlocDependantPourReclassement(elb)) {
if (indMaxiDroite === this.longueur() - 1) this.add(element, svg)
else this.insereElement(element, indMaxiDroite + 1, svg)
this.removeByInd(i)
indMaxiDroite--
i--
// Si l'objet qu'on vient de reclasser est le dernier objet final d'une
// implémentation de construction
// il faut recoller le corps de la construction avec lui
if (element.estElementFinal) {
const imp = element.impProto
const nb = imp.nbFinaux + imp.nbIntermediaires
for (let k = 0; k < nb; k++) {
const el1 = this.get(i)
if (indMaxiDroite === this.longueur() - 1) this.add(el1, svg)
else this.insereElement(el1, indMaxiDroite + 1, svg)
this.removeByInd(i)
indMaxiDroite--
i--
}
}
} else {
if (element.estElementFinal) {
// Il ne faut pas désolidariser le dernier élément final de son
// implémentation de prototype
const imp = element.impProto
const nb = imp.nbFinaux + imp.nbIntermediaires + 1
i -= nb
} else { i-- }
}
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction remontant d'un cran vers le début dans la liste l'objet elb et ceux dont il dépend
* @param elb
* @returns {boolean} renvoie false si le reclassement n'est pas possible
*/
CListeObjets.prototype.reclassUpOneStep = function (elb) {
let el = null
// var indicemini = 0;
// var indDebut = 0;
let indDebut
for (indDebut = 0; indDebut < this.longueur(); indDebut++) {
const elt = this.get(indDebut)
if (!elt.estDeNatureCalcul(Nat.or(NatCal.NCalculReelConstant, NatCal.NVariable))) break
}
const indicemini = indDebut
// Si l'élément à remonter est un élément final de construction ou une CImplementationProto il faut remonter tout le bloc.
const imp = elb.estElementFinal ? elb.impProto : (elb.estDeNature(NatObj.NImpProto) ? elb : null)
const indelb = (imp !== null) ? this.indexOf(imp) : this.indexOf(elb)
// On recherche vers le début à partir de elb l'indice du premier élément dont ne dépend pas elb;
// int i = indelb;
let trouve = false
const inddest = (imp === null) ? indelb : indelb + imp.nbFinaux + imp.nbIntermediaires
let i = indelb
while (!trouve && (i > indicemini)) {
i--
el = this.get(i)
if (el.estElementFinal) {
const imp2 = el.impProto
if (!elb.appartientABlocDependantPourReclassement(el)) {
trouve = true
indDebut = i - imp2.nbFinaux - imp2.nbIntermediaires
el = imp2
break
}
i = i - imp2.nbFinaux - imp2.nbIntermediaires
} else {
if (!elb.dependDeBlocPourReclassement(el)) {
trouve = true
indDebut = i
break
}
}
}
if (!trouve) return false
if (el.estDeNature(NatObj.NImpProto)) {
for (let j = 0; j <= el.nbFinaux + el.nbIntermediaires; j++) {
const e = this.get(indDebut)
this.removeByInd(indDebut)
if (inddest === this.longueur()) this.add(e)
else this.insert(inddest, e)
}
} else {
this.removeObj(el)
if (inddest === this.longueur()) this.add(el)
else this.insert(inddest, el)
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction remontant d'un cran verls la fin dans la liste l'objet elb et ceux dont il dépend
* @param elb
* @returns {boolean} renvoie false si le reclassement n'est pas possible
*/
CListeObjets.prototype.reclassDownOneStep = function (elb) {
let i, imp
let el = null
// Si l'élément à remonter est un élément final de construction il faut remonter tout le bloc.
const indelb = elb.estElementFinal ? this.indexOf(elb.impProto) : this.indexOf(elb)
// if (indelb == 0) return false; // On ne peut pas reclasser la constante pi vers la fin
if (elb.estElementFinal || elb.estDeNature(NatObj.NImpProto)) {
imp = elb.estElementFinal ? elb.impProto : elb
i = this.indexOf(imp) + imp.nbFinaux + imp.nbIntermediaires
if (i + 1 === this.longueur()) return false
} else if (indelb === this.longueur() - 1) return false
else i = indelb
let trouve = false
while (!trouve && (i < this.longueur() - 1)) {
i++
el = this.get(i)
if (el.estDeNature(NatObj.NImpProto)) {
i++
el = this.get(i)
}
if (!el.appartientABlocDependantPourReclassement(elb)) trouve = true
else {
if (el.impProto !== null) {
imp = el.impProto
i = this.indexOf(imp) + imp.nbFinaux + imp.nbIntermediaires
}
}
}
if (!trouve) return false
if (el.impProto !== null) {
imp = el.impProto
i = this.indexOf(imp)
for (let j = 0; j <= imp.nbFinaux + imp.nbIntermediaires; j++) {
const e = this.get(i + j)
// remove(e);
this.removeByInd(i + j)
this.insert(indelb + j, e)
}
} else {
this.removeObj(el)
this.insert(indelb, el)
}
this.updateIndexes()
this.determineDependancesCommentaires()
// Version 7.9.2 : plus de div plaqués sur le figure pour les éditeurs de formule et les variables
// auxquelles est associée un pane d'affichage avec bouton + - = mais un foreignElt (foreign object)
// dont on reclasse l'affichage au-dessus à chaque ajoute d'objet
// cela dot être mis sur la queue d'affichage
addQueue(() => {
this.reclassForeignElts()
})
return true
}
/**
* Fonction retirant du svg de la figure tous les gElements représentant les éléments graphiques
* et les recréant en rajoutant aussi les gElements représentant les objets ùmasqués si bMemeMasque
* est true et ceux représentant les objets intermédiaires de constructions
* @param svg
* @param couleurFond
* @param bMemeMasques
* @param bInterm
* @param inddeb L'inide de début de traitement
* @param nbObjMax Le nombre d'objets à utiliser
* @returns {void}
*/
CListeObjets.prototype.prepareForProtocol = function (svg, couleurFond, bMemeMasques, bInterm, inddeb, nbObjMax) {
this.setReady4MathJax(bMemeMasques, bInterm)
const self = this
addQueue(function () {
for (let i = inddeb; i <= nbObjMax; i++) {
const elb = self.get(i)
if (elb.estDeNature(NatObj.NTtObj) && (!elb.estElementIntermediaire() || bInterm)) {
elb.creeAffichage(svg, !bMemeMasques, couleurFond)
// Au départ tous les gElements représentant les objets graphiques sont masqué
elb.showgElt(false)
}
}
})
}
/**
* Fonction montrant ou cachant les gElements des objets graphiques de la figure pour la boîte de dialogue
* de protocole de la figure depuis l'indice indstart jusqu'à l'indice indFin
* @param indStart
* @param indFin
* @param bMemeMasques Si true, on montre aussi les éléments cachés
* @param bInterm Si true on montre aussi les objets intermédiares de construction
* @param {number} indMax L'indice maxi permis dans la liste d'objets
*/
CListeObjets.prototype.displayForProtocol = function (indStart, indFin, bMemeMasques, bInterm, indMax) {
for (let i = indStart; i <= indMax; i++) {
const elb = this.get(i)
if (elb.estDeNature(NatObj.NTtObj) && (!elb.estElementIntermediaire() || bInterm)) {
if (i <= indFin) {
/*
$(elb.g).attr("visibility", b ? "visible" : "hidden");
if (elb.estDeNature(NatObj.NObjNommable)) $(elb.gname).attr("visibility", b ? "visible" : "hidden");
*/
elb.showgElt(bMemeMasques || !elb.masque)
} else elb.showgElt(false)
}
}
}
CListeObjets.prototype.listeNoms = function () {
const s = this.longueur()
let ch = ''
for (let i = 0; i < s; i++) {
const el = this.get(i)
const st = el.getNom()
ch += (st === '') ? el.nom : st
if (i !== s - 1) ch += ', '
}
return ch
}
/**
* Fonction utiliée pour la boîte de dialogue de protocole
* Génére des noms pour les objets créés à partir de l'indice inddeb jusqu'à l'indice indmax
* @param inddeb
* @param indmax
* @param list
*/
CListeObjets.prototype.genereNoms = function (inddeb, indmax, list) {
let i, el
CAbscisseOrigineRep.ind = 0
COrdonneeOrigineRep.ind = 0
CUnitexRep.ind = 0
CUniteyRep.ind = 0
CArcDeCercleAncetre.ind = 0
CCercle.ind = 0
CSegment.ind = 0
CCommentaire.ind = 0
CDemiDroite.ind = 0
CDemiPlan.ind = 0
CEditeurFormule.ind = 0
CGrapheSuiteRec.ind = 0
CGrapheSuiteRecComplexe.ind = 0
CImage.ind = 0
CLatex.ind = 0
CLieuDeBase.ind = 0
CLieuDiscretDeBase.ind = 0
CLieuObjetAncetre.ind = 0
CMacro.ind = 0
CMarqueAngleAncetre.ind = 0
CMarqueSegment.ind = 0
CPt.ind = 0
CDroiteAncetre.ind = 0
CSurface.ind = 0
CValeurAffichee.ind = 0
// On regarde combien a figure contient de points ou de droites qu'il faut nommer. Si ce nombre est nférieur à 50
// On génère des noms construits de façon générique pour les points et droites, ce ui oblige pour chacun à faire une génération
// aléatoire et peut être chronophage sur les figures très lourdes obtenues par récursion par exemple.
// Sinon les points auront un nom commençant par Pt et le sdroites par dt
let compteur = 0
for (i = inddeb; i <= indmax; i++) {
el = this.get(i)
if (el.getNom() === '') compteur++
}
const nomsDynamiques = (compteur <= 100) && (this.longueur() <= 500)
for (i = inddeb; i <= indmax; i++) {
el = this.get(i)
if (el.getNom() === '') {
list.add(el)
if (nomsDynamiques) el.nom = el.genereNom()
else {
if (el.estDeNature(NatObj.NDroite)) el.nom = el.genereNom(getStr('rdt'))
else if (el.estDeNature(NatObj.NSegment)) el.nom = el.genereNom(getStr('seg'))
else if (el.estDeNature(NatObj.NTtPoint)) el.nom = el.genereNom(getStr('rpt'))
else el.nom = el.genereNom()
}
if (el.estDeNature(NatObj.NTtObj)) {
el.nomMasque = false
el.tailleNom = 13
}
} else {
if (el.estDeNature(NatObj.NObjNommable)) el.nomMasque = false
}
}
}
/**
* Fonction remettant le champ nom de tous les objets à ""
* @param taille La taille à affecter aux noms de points ou droites
*/
CListeObjets.prototype.effaceNoms = function (taille) {
for (const el of this.col) {
el.nom = ''
if (el.estDeNature(NatObj.NObjNommable)) {
el.tailleNom = taille
}
}
}
/**
* Fonction renvoyant le nombre de points liés l'objet el qui soient visibles et ne soient pas
* des objets intermediaires de construction
* @param el
* @returns {number}
*/
CListeObjets.prototype.nombrePointsLiesAVisibles = function (el) {
let compteur = 0
for (const elb of this.col) {
if (elb.estDeNature(NatObj.NPointLie)) {
if (elb.existe && !elb.masque && (elb.lieA() === el) && !el.estElementIntermediaire()) { compteur++ }
}
}
return compteur
}
CListeObjets.prototype.nombreFonctionsDerivables = function () {
let res = 0
for (const elb of this.col) {
if (!elb.estElementIntermediaire() && elb.getNatureCalcul() === NatCal.NFonction) {
if (elb.deriveePossible(0)) res++
}
}
return res
}
/**
* Fonction supprimant les implémentations de construction de la figure et remplaçant les objets
* intermédiaires et finaux par de vrais objets en renommant si nécessaire.
* @param {MtgApp} app L'application
*/
CListeObjets.prototype.fusionImpConst = function (app) {
const tropObjets = this.longueur() > 2000
let nbPtsRenommes = 0
let nbDtesRenommees = 0
let nbCalculsRenommes = 0
const debutNomsPts = this.genereDebutNomPourPoint('')
const debutNomsDtes = this.genereNomPourPointOuDroite('d', false)
const debutNomsCalculs = this.genereDebutNomPourCalcul('calc', this.longueur() - 1, [])
// On retire d'abord toutes les implémentations de constructions
let i = 0
let elb
while (i < this.longueur()) {
elb = this.get(i)
if (elb.estDeNature(NatObj.NImpProto)) { this.remove(i) } else i++
}
for (const elb of this.col) {
if (elb.estElementIntermediaire()) {
if (elb.estDeNature(NatObj.NTtObj)) elb.creeAffichage(app.svgFigure, true, app.doc.couleurFond)
// On renomme les points ou droites intermédiaires si leur nom existe déjà
if (elb.estDeNature(NatObj.NObjNommable)) {
const ancienNom = elb.nom
if (ancienNom !== '') {
if (tropObjets) {
if (elb.estDeNature(NatObj.NTtPoint)) {
nbPtsRenommes++
elb.donneNom(debutNomsPts + nbPtsRenommes)
} else { // Cas d'une droite
nbDtesRenommees++
elb.donneNom(debutNomsDtes + nbDtesRenommees)
}
} else {
const ancienNom = elb.nom
if (this.existePointOuDroiteMemeNom(elb, ancienNom)) {
const nouveauNom = this.genereNomPourPointOuDroite(ancienNom.charAt(0))
elb.donneNom(nouveauNom)
}
}
}
} else {
// Il faut renommer aussi les calculs intermédiaires ayant même
// nom que d'autres calculs créés après implémentation de la construction
if (elb.estDeNatureCalcul(NatCal.NTtCalcNomme)) {
let nouveauNom
const ancienNom = elb.getNom()
if (tropObjets) {
nbCalculsRenommes++
nouveauNom = debutNomsCalculs + nbCalculsRenommes
// this.remplaceNomValeurDynamiqueDansCommentairesOuLatexDepDe(ancienNom, nouveauNom, elb)
elb.nomCalcul = nouveauNom
} else {
if (this.existeCalculOuVariableOuFonctionOuParametreMemeNom(elb, ancienNom, true)) {
nouveauNom = this.genereNomPourCalcul(ancienNom, false)
this.remplaceNomValeurDynamiqueDansCommentairesOuLatexDepDe(ancienNom, nouveauNom, elb)
elb.nomCalcul = nouveauNom
}
}
}
}
elb.impProto = null
elb.estElementFinal = false
} else {
if (elb.estElementFinal) {
elb.impProto = null
elb.estElementFinal = false
}
}
}
// Ajout version 4.8.0
this.updateIndexes()
//
// On reconstruit toutes les formules de la figure
this.reconstruitChainesCalcul()
}
/**
* Fonction recalculant les éléments de la liste de nature nat
* @param nat
* @param {boolean} infoRandom Si true les calculs aléatoires par rand() sont réinitialisés
* @param {Dimf} dimfen les dimensions de la fenêtre
*/
CListeObjets.prototype.positionneParNat = function (nat, infoRandom, dimfen) {
for (const el of this.col) {
if (el.estDeNature(nat)) el.positionne(infoRandom, dimfen)
}
}
CListeObjets.prototype.positionneTikz = function (infoRandom, dimfen) {
for (const el of this.col) {
el.positionneTikz(infoRandom, dimfen)
}
}
CListeObjets.prototype.tikzXcoord = function (x, dimf, bu) {
// Si la figure a une longueur unité et qu'on a choisi de l'utiliser, bu.infoLength contient
// la longueur en cm de la longueur unité
// Sinon bu.infoLength contient la largeur en com de la figure
if (bu.useFigUnity) return x / this.pointeurLongueurUnite.rendLongueur() * bu.infoLength
else return x * bu.infoLength / dimf.x
// double res = (double) Toolkit.getDefaultToolkit().getScreenResolution() / 2.54;
// On suppose que la largeur de la figure sera de 12 cm
}
CListeObjets.prototype.tikzYcoord = function (y, dimf, bu) {
if (bu.useFigUnity) return (dimf.y - y) / this.pointeurLongueurUnite.rendLongueur() * bu.infoLength
else return (dimf.y - y) * bu.infoLength / dimf.x
}
CListeObjets.prototype.tikzLongueur = function (lon, dimf, bu) {
if (bu.useFigUnity) {
return lon / this.pointeurLongueurUnite.rendLongueur() * bu.infoLength
} else return lon * bu.infoLength / dimf.x
}
CListeObjets.prototype.taillePlus = function () {
let done = false
for (const el of this.col) {
if (el.estDeNature(NatObj.NAffLieAPoint)) {
if (el.taillePolice < 80) {
el.taillePolice++
done = true
}
} else {
if (el.estDeNature(NatObj.NObjNommable)) {
if (el.tailleNom < 80) {
el.tailleNom++
done = true
}
}
}
}
return done
}
CListeObjets.prototype.tailleMoins = function () {
let done = false
for (const el of this.col) {
if (el.estDeNature(NatObj.NAffLieAPointSaufImEd)) {
if (el.taillePolice > 10) {
el.taillePolice--
done = true
}
} else {
if (el.estDeNature(NatObj.NObjNommable)) {
if (el.tailleNom > 10) {
el.tailleNom--
done = true
}
}
}
}
return done
}
/**
* Fonction appelée quand on augment ou diminue la taille de toutes les polices
* @param svg
* @param couleurFond
* @param masquage
* @returns {void}
*/
CListeObjets.prototype.updateDisplays = function (svg, couleurFond, masquage) {
this.setReady4MathJax()
const self = this
addQueue(function () {
for (const elb of self.col) {
// Il faut mettre à jour aussi les lieux d'objets dont l'objet générant le lieu est un affichage
if (elb.existe && (elb.estDeNature(NatObj.NAffLieAPointSaufImEd) ||
(elb.estDeNature(NatObj.NLieuObjet) && elb.elementAssocie.estDeNature(NatObj.NAffLieAPoint))) &&
(elb.hasg(masquage))) {
const oldg = elb.g
const newg = elb.createg(svg, couleurFond)
svg.replaceChild(newg, oldg)
elb.g = newg
} else {
if (elb.estDeNature(NatObj.NObjNommable) && !elb.estElementIntermediaire() && elb.hasg(masquage)) elb.updateName(svg, true)
}
}
})
}
/**
* Fonction renvoyant true si une des macros de construction itérative ou récusive éventuelle de la figure
* dépend du prototype proto
* @param {CPrototype} proto
* @returns {boolean}
*/
CListeObjets.prototype.depDeProto = function (proto) {
for (const el of this.col) {
if (el.depDeProto(proto)) return true
}
return false
}