import { texNombre2 } from '../outils.js'
import { simplify, parse, unit, max, add, subtract, abs, log10, random, round, isConstantNode } from 'mathjs'
import { aleaName } from '../outilsMathjs.js'
import { GVGraphicObject } from './elements.js'
/**
* Grandeur, methods for operations
*
*/
export class GVGrandeur {
value /** number */
precision /** number */
unit /** string */
toFixed /** number */
nameAndValue /** string */
_name /** string */
calcul /** string */
constructor (name /** string | GVPoint[] */, value /** number */, precision /** number */ = 1, unit /** string */ = '') {
this.value = round(value, precision)
this.precision = precision
this.unit = unit
this.toFixed = round(this.value, this.precision)
this.name = name
}
set name (newname /** string | GVPoint[] */) {
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/** (string | GVGraphicObject)[] */) {
this.name = aleaName(name.map(x => {
if (x instanceof GVGraphicObject) {
return x.name
} else {
return x
}
}), name.length).join('')
}
multiply (a /** GVGrandeur */) {
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(isConstantNode(calcul) ? calcul.toString() : calcul.args[0].toString()),
this.precision + a.precision,
isConstantNode(calcul) ? '' : calcul.args[1].toString()
)
}
divide (a /** GVGrandeur */) {
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(isConstantNode(calcul) ? calcul.toString() : calcul.args[0].toString()),
this.precision - a.precision,
isConstantNode(calcul) ? '' : calcul.args[1].toString()
)
}
add (a /** GVGrandeur */) {
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(isConstantNode(calcul) ? calcul.toString() : calcul.args[0].toString()),
max(this.precision, a.precision),
isConstantNode(calcul) ? '' : calcul.args[1].toString()
)
}
subtract (a /** GVGrandeur */) {
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(isConstantNode(calcul) ? calcul.toString() : calcul.args[0].toString()),
max(this.precision, a.precision),
isConstantNode(calcul) ? '' : calcul.args[1].toString()
)
}
hypotenuse (a /** GVGrandeur */) {
return a.pow(2).add(this.pow(2)).sqrt()
}
/**
* this^n
* @param {number} n // Integer
* @returns {GVGrandeur}
*/
pow (n /** number */) /** GVGrandeur */ {
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 () /** GVGrandeur */ {
return new GVGrandeur('\\sqrt{' + this.name + '}', Math.pow(this.toFixed, 0.5), Math.floor(0.5 * this.precision), 'cm')
}
abs () /** GVGrandeur */ {
return new GVGrandeur(
this._name,
abs(this.value),
this.precision,
this.unit
)
}
neg () /** GVGrandeur */ {
return new GVGrandeur(
'-' + this.name,
-this.value,
this.precision,
this.unit
)
}
to (newUnit /** string */) /** GVGrandeur */ {
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 /** number */ = 0, nmax /** number */ = 1, digit /** number */ = max(0, -log10(abs(nmax - nmin))), name /** string */ = '', unit /** string */ = '') /** GVGrandeur */ {
return new GVGrandeur(
name,
round(random(nmin, nmax), max(digit, 0)),
digit,
unit
)
}