modules/aleaFigure/grandeurs.js

import { texNombre2 } from '../outils.js'
import { simplify, parse, unit, max, add, subtract, abs, log10, random, round } from 'mathjs'
import { aleaName } from '../outilsMathjs.js'
import { GVGraphicObject } from './elements.js'
/**
 * Grandeur, methods for operations
 *
 */
export class GVGrandeur {
  constructor (name, value, precision = 1, unit = '') {
    this.value = round(value, precision)
    this.precision = precision
    this.unit = unit
    this.toFixed = round(this.value, this.precision)
    this.name = name
  }

  set name (newname) {
    if (typeof newname === 'string') {
      this._name = newname
    } else {
      this._name = (aleaName(newname).map(x => x.name)).join('')
    }
    this.nameAndValue = `$ {${this.name}=${texNombre2(this.toFixed).replace(',', '{,}')}~${this.unit.replace('deg', '\\degree')}}$`.replace('~\\degree', '\\degree')
  }

  get name () { return this._name }
  format () {
    return `{${texNombre2(this.toFixed).replace(',', '{,}')}~${this.unit.replace('deg', '\\degree')}}`.replace('~\\degree', '\\degree')
  }

  aleaName (...name) {
    this.name = aleaName(name.map(x => {
      if (x instanceof GVGraphicObject) {
        return x.name
      } else {
        return x
      }
    }), name.length).join('')
  }

  multiply (a) {
    const expression = simplify([this.name, a.name].filter(x => x !== '').join('*').replaceAll('{', '(').replaceAll('}', ')')).toString()
    const calcul = parse(unit(this.toFixed + this.unit).multiply(unit(a.toFixed + a.unit)).toString())
    return new GVGrandeur(expression, parseFloat(calcul.isConstantNode ? calcul.toString() : calcul.args[0].toString()), this.precision + a.precision, calcul.isConstantNode ? '' : calcul.args[1].toString())
  }

  divide (a) {
    const expression = simplify([this.name, a.name].filter(x => x !== '').join('/').replaceAll('{', '(').replaceAll('}', ')')).toString()
    const calcul = parse(unit(this.toFixed + this.unit).divide(unit(a.toFixed + a.unit)).toString())
    return new GVGrandeur(expression, parseFloat(calcul.isConstantNode ? calcul.toString() : calcul.args[0].toString()), this.precision - a.precision, calcul.isConstantNode ? '' : calcul.args[1].toString())
  }

  add (a) {
    const expression = simplify([this.name, a.name].filter(x => x !== '').join('+').replaceAll('{', '(').replaceAll('}', ')')).toString()
    const calcul = parse(add(unit(this.toFixed + this.unit), unit(a.toFixed + a.unit)).toString())
    return new GVGrandeur(expression, parseFloat(calcul.isConstantNode ? calcul.toString() : calcul.args[0].toString()), max(this.precision, a.precision), calcul.isConstantNode ? '' : calcul.args[1].toString())
  }

  subtract (a) {
    const expression = simplify([this.name, a.name].filter(x => x !== '').join('-').replaceAll('{', '(').replaceAll('}', ')')).toString()
    const calcul = parse(subtract(unit(this.toFixed + this.unit), unit(a.toFixed + a.unit)).toString())
    return new GVGrandeur(expression, parseFloat(calcul.isConstantNode ? calcul.toString() : calcul.args[0].toString()), max(this.precision, a.precision), calcul.isConstantNode ? '' : calcul.args[1].toString())
  }

  hypotenuse (a) {
    return a.pow(2).add(this.pow(2)).sqrt()
  }

  /**
     * this^n
     * @param {number} n // Integer
     * @returns {GVGrandeur}
     */
  pow (n) {
    return new GVGrandeur(this.name + '^{' + n + '}', Math.pow(this.toFixed, n), n * this.precision, this.unit + '^' + n)
  }

  /**
     * this^n
     * @param n // Integer
     * @returns {GVGrandeur}
     */
  sqrt () {
    return new GVGrandeur('\\sqrt{' + this.name + '}', Math.pow(this.toFixed, 0.5), Math.floor(0.5 * this.precision), 'cm')
  }

  abs () {
    return new GVGrandeur(this._name, abs(this.value), this.precision, this.unit)
  }

  neg () {
    return new GVGrandeur('-' + this.name, -this.value, this.precision, this.unit)
  }

  to (newUnit) {
    const thenumber = abs(unit(this.value, this.unit))
    const conversion = abs(thenumber.to(newUnit))
    const precision = Math.max(0, this.precision - log10(parse(conversion.toString()).args[0].value / parse(thenumber.toString()).args[0].value))
    return new GVGrandeur(this.name, parse(conversion.toString()).args[0].value, precision, newUnit)
  }
}
/**
 * Quantity random
 * @param {number} nmin
 * @param {number} nmax
 * @param {number} digit
 * @param {string} name
 * @param {string} unit
 * @returns {GVGrandeur}
 */
export function qrandom (nmin = 0, nmax = 1, digit = max(0, -log10(abs(nmax - nmin))), name = '', unit = '') {
  return new GVGrandeur(name, round(random(nmin, nmax), max(digit, 0)), digit, unit)
}