Files
orion4d-Calculator_Pro/nodes.py
T
2025-06-29 17:08:54 +02:00

187 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fichier : scientific_calculator/nodes.py
# Version avec la calculatrice corrigée pour éviter l'erreur "float modulo".
import math
# ==========================================================
# CATEGORIE GLOBALE POUR TOUS LES NŒUDS
# ==========================================================
MAIN_CATEGORY = "CalculatorPro"
# ===============================================
# CLASSE 1 : CALCULATRICE SCIENTIFIQUE (CORRIGÉE)
# ===============================================
class ScientificCalculatorTriNode:
FUNCTION_CHOICES=["a+b","a-b","a*b","a/b","a^b","a mod b","a+c","a-c","a*c","a/c","a^c","a mod c","b+c","b-c","b*c","b/c","b^c","b mod c","min(a,b)","max(a,b)","min(a,c)","max(a,c)","min(b,c)","max(b,c)","a+b+c","a*b*c","sin(a)","cos(a)","tan(a)","sqrt(a)","log(a)","abs(a)","round(a)","sin(b)","cos(b)","tan(b)","sqrt(b)","log(b)","abs(b)","round(b)","sin(c)","cos(c)","tan(c)","sqrt(c)","log(c)","abs(c)","round(c)",]
CATEGORY = f"{MAIN_CATEGORY}/Math"
@classmethod
def INPUT_TYPES(cls): return {"required":{"a":("FLOAT",{"default":0.0,"step":0.01}),"b":("FLOAT",{"default":0.0,"step":0.01}),"c":("FLOAT",{"default":0.0,"step":0.01}),"function":(cls.FUNCTION_CHOICES,{"default":"a+b"}),}}
RETURN_TYPES,RETURN_NAMES,FUNCTION=("FLOAT","STRING"),("result","output_str"),"calculate"
# --- MÉTHODE CORRIGÉE ---
def calculate(self, a, b, c, function):
res, txt, fmt = 0.0, "", "g"
fa, fb, fc = f"{a:{fmt}}", f"{b:{fmt}}", f"{c:{fmt}}"
try:
if function == "a+b": res, txt = a + b, f"{fa} + {fb} = {a+b:{fmt}}"
elif function == "a-b": res, txt = a - b, f"{fa} - {fb} = {a-b:{fmt}}"
elif function == "a*b": res, txt = a * b, f"{fa} × {fb} = {a*b:{fmt}}"
elif function == "a/b": res, txt = (a / b, f"{fa} ÷ {fb} = {a/b:{fmt}}") if b != 0 else (float('nan'), "Err:Div/0")
elif function == "a^b": res, txt = a ** b, f"{fa} ^ {fb} = {a**b:{fmt}}"
elif function == "a mod b": res, txt = (a % b, f"{fa} mod {fb} = {a%b:{fmt}}") if b != 0 else (float('nan'), "Err:Mod/0")
elif function == "a+c": res, txt = a + c, f"{fa} + {fc} = {a+c:{fmt}}"
elif function == "a-c": res, txt = a - c, f"{fa} - {fc} = {a-c:{fmt}}"
elif function == "a*c": res, txt = a * c, f"{fa} × {fc} = {a*c:{fmt}}"
elif function == "a/c": res, txt = (a / c, f"{fa} ÷ {fc} = {a/c:{fmt}}") if c != 0 else (float('nan'), "Err:Div/0")
elif function == "a^c": res, txt = a ** c, f"{fa} ^ {fc} = {a**c:{fmt}}"
elif function == "a mod c": res, txt = (a % c, f"{fa} mod {fc} = {a%c:{fmt}}") if c != 0 else (float('nan'), "Err:Mod/0")
elif function == "b+c": res, txt = b + c, f"{fb} + {fc} = {b+c:{fmt}}"
elif function == "b-c": res, txt = b - c, f"{fb} - {fc} = {b-c:{fmt}}"
elif function == "b*c": res, txt = b * c, f"{fb} × {fc} = {b*c:{fmt}}"
elif function == "b/c": res, txt = (b / c, f"{fb} ÷ {fc} = {b/c:{fmt}}") if c != 0 else (float('nan'), "Err:Div/0")
elif function == "b^c": res, txt = b ** c, f"{fb} ^ {fc} = {b**c:{fmt}}"
elif function == "b mod c": res, txt = (b % c, f"{fb} mod {fc} = {b%c:{fmt}}") if c != 0 else (float('nan'), "Err:Mod/0")
elif function == "min(a,b)": res, txt = min(a,b), f"min({fa},{fb})={min(a,b):{fmt}}"
elif function == "max(a,b)": res, txt = max(a,b), f"max({fa},{fb})={max(a,b):{fmt}}"
elif function == "min(a,c)": res, txt = min(a,c), f"min({fa},{fc})={min(a,c):{fmt}}"
elif function == "max(a,c)": res, txt = max(a,c), f"max({fa},{fc})={max(a,c):{fmt}}"
elif function == "min(b,c)": res, txt = min(b,c), f"min({fb},{fc})={min(b,c):{fmt}}"
elif function == "max(b,c)": res, txt = max(b,c), f"max({fb},{fc})={max(b,c):{fmt}}"
elif function == "a+b+c": res, txt = a + b + c, f"{fa}+{fb}+{fc}={a+b+c:{fmt}}"
elif function == "a*b*c": res, txt = a * b * c, f"{fa}×{fb}×{fc}={a*b*c:{fmt}}"
elif function == "sin(a)": res, txt = math.sin(a), f"sin({fa})={math.sin(a):{fmt}}"
elif function == "cos(a)": res, txt = math.cos(a), f"cos({fa})={math.cos(a):{fmt}}"
elif function == "tan(a)": res, txt = math.tan(a), f"tan({fa})={math.tan(a):{fmt}}"
elif function == "sqrt(a)": res, txt = (math.sqrt(a), f"sqrt({fa})={math.sqrt(a):{fmt}}") if a >= 0 else (float('nan'), "Err:sqrt<0")
elif function == "log(a)": res, txt = (math.log(a), f"log({fa})={math.log(a):{fmt}}") if a > 0 else (float('nan'), "Err:log<=0")
elif function == "abs(a)": res, txt = abs(a), f"abs({fa})={abs(a):{fmt}}"
elif function == "round(a)": res, txt = round(a), f"round({fa})={round(a):{fmt}}"
elif function == "sin(b)": res, txt = math.sin(b), f"sin({fb})={math.sin(b):{fmt}}"
elif function == "cos(b)": res, txt = math.cos(b), f"cos({fb})={math.cos(b):{fmt}}"
elif function == "tan(b)": res, txt = math.tan(b), f"tan({fb})={math.tan(b):{fmt}}"
elif function == "sqrt(b)": res, txt = (math.sqrt(b), f"sqrt({fb})={math.sqrt(b):{fmt}}") if b >= 0 else (float('nan'), "Err:sqrt<0")
elif function == "log(b)": res, txt = (math.log(b), f"log({fb})={math.log(b):{fmt}}") if b > 0 else (float('nan'), "Err:log<=0")
elif function == "abs(b)": res, txt = abs(b), f"abs({fb})={abs(b):{fmt}}"
elif function == "round(b)": res, txt = round(b), f"round({fb})={round(b):{fmt}}"
elif function == "sin(c)": res, txt = math.sin(c), f"sin({fc})={math.sin(c):{fmt}}"
elif function == "cos(c)": res, txt = math.cos(c), f"cos({fc})={math.cos(c):{fmt}}"
elif function == "tan(c)": res, txt = math.tan(c), f"tan({fc})={math.tan(c):{fmt}}"
elif function == "sqrt(c)": res, txt = (math.sqrt(c), f"sqrt({fc})={math.sqrt(c):{fmt}}") if c >= 0 else (float('nan'), "Err:sqrt<0")
elif function == "log(c)": res, txt = (math.log(c), f"log({fc})={math.log(c):{fmt}}") if c > 0 else (float('nan'), "Err:log<=0")
elif function == "abs(c)": res, txt = abs(c), f"abs({fc})={abs(c):{fmt}}"
elif function == "round(c)": res, txt = round(c), f"round({fc})={round(c):{fmt}}"
else: res, txt = float('nan'), f"Fonction non reconnue: {function}"
except Exception as e:
res, txt = float('nan'), f"Erreur: {e}"
return (float(res), str(txt))
# ==========================================================
# SECTION 2 : CONVERTISSEURS
# ==========================================================
class UniversalConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
@classmethod
def INPUT_TYPES(cls): return {"optional":{"float_in":("FLOAT",{"default":0.0,"forceInput":True}),"int_in":("INT",{"default":0,"forceInput":True}),"string_in":("STRING",{"default":"","forceInput":True}),"bool_in":("BOOLEAN",{"default":False,"forceInput":True}),}}
RETURN_TYPES,RETURN_NAMES,FUNCTION=("FLOAT","INT","STRING","BOOLEAN"),("FLOAT","INT","STRING","BOOLEAN"),"convert"
def convert(self,float_in=None,int_in=None,string_in=None,bool_in=None):
out_float,out_int,out_string,out_bool=0.0,0,"",False
if float_in is not None:out_float,out_int,out_string,out_bool=float(float_in),int(float_in),str(float_in),bool(float_in)
elif int_in is not None:out_float,out_int,out_string,out_bool=float(int_in),int(int_in),str(int_in),bool(int_in)
elif string_in is not None:
out_string=str(string_in)
try:out_float,out_int=float(string_in),int(float(string_in))
except(ValueError,TypeError):out_float,out_int=0.0,0
out_bool=string_in.lower()in['true','1','t','y','yes','vrai','o','oui']
elif bool_in is not None:
out_bool,out_float,out_int,out_string=bool(bool_in),1.0 if bool_in else 0.0,1 if bool_in else 0,str(bool_in)
return(out_float,out_int,out_string,out_bool)
class ManualRateConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "calculate"
OPERATION_CHOICES = ["Multiplier par le taux", "Diviser par le taux"]
@classmethod
def INPUT_TYPES(cls): return {"required": {"amount": ("FLOAT", {"default": 100.0}), "manual_rate": ("FLOAT", {"default": 1.07, "step": 0.0001}), "operation": (cls.OPERATION_CHOICES,)}}
def calculate(self, amount, manual_rate, operation):
if operation == self.OPERATION_CHOICES[0]: result = amount * manual_rate; txt = f"{amount:.2f} × {manual_rate} = {result:.2f}"
else:
if manual_rate == 0: return (float('nan'), "Erreur: Taux ne peut pas être zéro.")
result = amount / manual_rate; txt = f"{amount:.2f} ÷ {manual_rate} = {result:.2f}"
return (result, txt)
class LengthConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
UNITS = {"Mètre (m)": 1.0, "Centimètre (cm)": 0.01, "Millimètre (mm)": 0.001, "Kilomètre (km)": 1000.0, "Décimètre (dm)": 0.1, "Micromètre (µm)": 1e-6, "Nanomètre (nm)": 1e-9, "Angstrom (Å)": 1e-10, "Picomètre (pm)": 1e-12, "Femtomètre (fm)": 1e-15, "Pouce (in)": 0.0254, "Pied (ft)": 0.3048, "Yard (yd)": 0.9144, "Mile (mi)": 1609.344, "Mille marin (NM)": 1852.0, "Année-lumière (al)": 9.461e15, "Parsec (pc)": 3.086e16, "Unité Astronomique (ua)": 1.496e11, "Rayon terrestre (RT)": 6.371e6, "Longueur de Planck (lₚ)": 1.616e-35, "Lieue (4km)": 4000.0, "Toise (1.95m)": 1.949, "Aune (1.2m)": 1.188}
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "convert"
@classmethod
def INPUT_TYPES(cls): return {"required": {"value": ("FLOAT", {"default": 1.0}), "from_unit": (list(cls.UNITS.keys()),), "to_unit": (list(cls.UNITS.keys()),)}}
def convert(self, value, from_unit, to_unit):
result = (value * self.UNITS[from_unit]) / self.UNITS[to_unit]
return (result, f"{value:g} {from_unit.split(' (')[0]} = {result:g} {to_unit.split(' (')[0]}")
class MassConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
UNITS = {"Gramme (g)": 1.0, "Kilogramme (kg)": 1000.0, "Milligramme (mg)": 0.001, "Microgramme (µg)": 1e-6, "Tonne (t)": 1_000_000.0, "Livre (lb)": 453.592, "Once (oz)": 28.3495, "Grain (gr)": 0.0648, "Stone (st)": 6350.29, "Tonne UK (long ton)": 1_016_050.0, "Tonne US (short ton)": 907_185.0}
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "convert"
@classmethod
def INPUT_TYPES(cls): return {"required": {"value": ("FLOAT", {"default": 1.0}), "from_unit": (list(cls.UNITS.keys()),), "to_unit": (list(cls.UNITS.keys()),)}}
def convert(self, value, from_unit, to_unit):
result = (value * self.UNITS[from_unit]) / self.UNITS[to_unit]
return (result, f"{value:g} {from_unit.split(' (')[0]} = {result:g} {to_unit.split(' (')[0]}")
class VolumeConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
UNITS = {"Litre (L)": 1.0, "Millilitre (ml/cc)": 0.001, "Mètre cube (m³)": 1000.0, "Centilitre (cL)": 0.01, "Décilitre (dL)": 0.1, "Hectolitre (hL)": 100.0, "Gallon US (gal)": 3.78541, "Gallon Impérial (gal)": 4.54609, "Quart US (qt)": 0.946353, "Pinte US (pt)": 0.473176, "Pinte Impériale (pt)": 0.568261, "Cup US": 0.236588, "Fluid Ounce US (fl oz)": 0.0295735, "Fluid Ounce Impérial (fl oz)": 0.0284131, "Cuillère à soupe (15ml)": 0.015, "Cuillère à café (5ml)": 0.005, "Baril de pétrole (bbl)": 158.987, "Stère (bois)": 1000.0, "Pied cube (ft³)": 28.3168, "Pouce cube (in³)": 0.0163871}
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "convert"
@classmethod
def INPUT_TYPES(cls): return {"required": {"value": ("FLOAT", {"default": 1.0}), "from_unit": (list(cls.UNITS.keys()),), "to_unit": (list(cls.UNITS.keys()),)}}
def convert(self, value, from_unit, to_unit):
result = (value * self.UNITS[from_unit]) / self.UNITS[to_unit]
return (result, f"{value:g} {from_unit.split(' (')[0]} = {result:g} {to_unit.split(' (')[0]}")
class DataConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
UNITS = {"Octet (Byte)": 1.0, "Bit (b)": 1/8, "Kilo-octet (KB, 10³ B)": 1000.0, "Méga-octet (MB, 10⁶ B)": 1e6, "Giga-octet (GB, 10⁹ B)": 1e9, "Téra-octet (TB, 10¹² B)": 1e12, "Péta-octet (PB, 10¹⁵ B)": 1e15, "Kibioctet (KiB, 2¹⁰ B)": 1024.0, "Mébioctet (MiB, 2²⁰ B)": 1024.0**2, "Gibioctet (GiB, 2³⁰ B)": 1024.0**3, "Tébioctet (TiB, 2⁴⁰ B)": 1024.0**4, "Pébioctet (PiB, 2⁵⁰ B)": 1024.0**5}
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "convert"
@classmethod
def INPUT_TYPES(cls): return {"required": {"value": ("FLOAT", {"default": 1.0}), "from_unit": (list(cls.UNITS.keys()),), "to_unit": (list(cls.UNITS.keys()),)}}
def convert(self, value, from_unit, to_unit):
result = (value * self.UNITS[from_unit]) / self.UNITS[to_unit]
return (result, f"{value:g} {from_unit.split(' (')[0]} = {result:g} {to_unit.split(' (')[0]}")
class TimeConverterNode:
CATEGORY = f"{MAIN_CATEGORY}/Converters"
UNITS = {"Seconde (s)": 1.0, "Milliseconde (ms)": 0.001, "Microseconde (µs)": 1e-6, "Nanoseconde (ns)": 1e-9, "Picoseconde (ps)": 1e-12, "Temps de Planck (tₚ)": 5.391e-44, "Minute (min)": 60.0, "Heure (h)": 3600.0, "Jour (d)": 86400.0, "Semaine (sem)": 604800.0, "Mois (30.44j)": 2629746.0, "Année (365.24j)": 31556952.0, "Année julienne (365.25j)": 31557600.0, "Décennie": 315569520.0, "Siècle": 3155695200.0}
RETURN_TYPES, RETURN_NAMES, FUNCTION = ("FLOAT", "STRING"), ("result", "output_str"), "convert"
@classmethod
def INPUT_TYPES(cls): return {"required": {"value": ("FLOAT", {"default": 1.0}), "from_unit": (list(cls.UNITS.keys()),), "to_unit": (list(cls.UNITS.keys()),)}}
def convert(self, value, from_unit, to_unit):
result = (value * self.UNITS[from_unit]) / self.UNITS[to_unit]
return (result, f"{value:g} {from_unit.split(' (')[0]} = {result:g} {to_unit.split(' (')[0]}")
# =================================================
# ENREGISTREMENT DE TOUS LES NŒUDS POUR COMFYUI
# =================================================
NODE_CLASS_MAPPINGS = {
"ScientificCalculatorTri": ScientificCalculatorTriNode,
"UniversalConverter": UniversalConverterNode,
"ManualRateConverter": ManualRateConverterNode,
"LengthConverter": LengthConverterNode,
"MassConverter": MassConverterNode,
"VolumeConverter": VolumeConverterNode,
"DataConverter": DataConverterNode,
"TimeConverter": TimeConverterNode,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ScientificCalculatorTri": "🧮 Calculatrice Scientifique",
"UniversalConverter": "🔧 Convertisseur Universel",
"ManualRateConverter": "💱 Convertisseur Manuel (Taux)",
"LengthConverter": "📏 Convertisseur de Longueur",
"MassConverter": "⚖️ Convertisseur de Masse",
"VolumeConverter": "💧 Convertisseur de Volume",
"DataConverter": "💾 Convertisseur de Données",
"TimeConverter": "⏱️ Convertisseur de Temps",
}