Actualización de la configuración de la ventana y ajustes en la posición de los elementos. Se añade soporte para la conversión a LaTeX en varias partes del código, incluyendo nuevas funcionalidades en el motor de evaluación y en la clase de herramientas de Sympy. Se mejora la gestión dinámica de clases de corchetes, eliminando dependencias de clases codificadas y optimizando la recarga de clases. También se incorpora la opción de registrar versiones en minúscula de las clases en el registro de tipos.

This commit is contained in:
Miguel 2025-06-02 23:05:54 +02:00
parent ee24ef2615
commit 449d503213
7 changed files with 189 additions and 30 deletions

134
custom_types/latex_type.py Normal file
View File

@ -0,0 +1,134 @@
"""
Clase híbrida para conversión LaTeX - ADAPTADA AL NUEVO SISTEMA
"""
from sympy_Base import SympyClassBase
import sympy
import re
class Class_LaTeX(SympyClassBase):
"""Clase híbrida para conversión de expresiones a formato LaTeX"""
def __new__(cls, value_input):
"""Crear objeto SymPy válido"""
obj = SympyClassBase.__new__(cls)
return obj
def __init__(self, expression):
"""Inicialización de LaTeX"""
# Si el input es string, intentar parsearlo como expresión de SymPy
if isinstance(expression, str):
try:
# Parsear la expresión string a objeto SymPy
parsed_expr = sympy.sympify(expression)
self._expression = parsed_expr
except Exception as e:
# Si no se puede parsear, mantener como string
self._expression = expression
else:
# Si ya es un objeto SymPy, usarlo directamente
self._expression = expression
# Generar código LaTeX
try:
if hasattr(self._expression, '__class__') and hasattr(sympy, 'latex'):
self._latex_code = sympy.latex(self._expression)
else:
self._latex_code = str(self._expression)
except Exception:
self._latex_code = str(self._expression)
# Llamar al constructor base con el código LaTeX como valor de display
super().__init__(self._expression, self._latex_code)
def __str__(self):
"""Representación string que muestra el código LaTeX"""
return self._latex_code
def _sympystr(self, printer):
"""Representación SymPy string"""
return self._latex_code
def latex_code(self):
"""Retorna el código LaTeX generado"""
return self._latex_code
def original_expression(self):
"""Retorna la expresión original"""
return self._expression
def to_image(self, filename=None, dpi=150):
"""
Convierte el LaTeX a imagen (requiere matplotlib)
"""
try:
import matplotlib.pyplot as plt
import matplotlib
# Configurar matplotlib para usar LaTeX
matplotlib.rcParams['text.usetex'] = True
fig, ax = plt.subplots(figsize=(10, 2))
ax.text(0.5, 0.5, f'${self._latex_code}$',
horizontalalignment='center',
verticalalignment='center',
fontsize=16,
transform=ax.transAxes)
ax.axis('off')
if filename:
plt.savefig(filename, dpi=dpi, bbox_inches='tight')
plt.close()
return f"LaTeX guardado como imagen en: {filename}"
else:
plt.show()
return "LaTeX mostrado en pantalla"
except ImportError:
return "Error: matplotlib no está instalado. Instalar con: pip install matplotlib"
except Exception as e:
return f"Error generando imagen: {e}"
@staticmethod
def Helper(input_str):
"""Ayuda contextual para LaTeX"""
if re.match(r"^\s*[Ll]atex\b", input_str, re.IGNORECASE):
return '''LaTeX - Conversión de expresiones matemáticas a código LaTeX
Uso: LaTeX[expresion] o latex[expresion]
Ejemplos:
LaTeX[x**2 + 2*x + 1] x^{2} + 2 x + 1
LaTeX[sin(x)/cos(x)] \\frac{\\sin{\\left(x \\right)}}{\\cos{\\left(x \\right)}}
LaTeX[Integral(x, x)] \\int x\\,dx
LaTeX[sqrt(x**2 + y**2)] \\sqrt{x^{2} + y^{2}}
Métodos disponibles:
.latex_code() - Obtiene el código LaTeX
.original_expression() - Obtiene la expresión original
.to_image() - Convierte a imagen (requiere matplotlib)
Nota: Las expresiones pueden ser strings o objetos SymPy'''
return None
@staticmethod
def PopupFunctionList():
"""Lista de métodos sugeridos para autocompletado de LaTeX"""
return [
("latex_code", "Obtiene el código LaTeX generado"),
("original_expression", "Obtiene la expresión matemática original"),
("to_image", "Convierte el LaTeX a imagen (requiere matplotlib)"),
]
def register_classes_in_module():
"""
Devuelve una lista de clases definidas en este módulo para ser registradas.
"""
return [
("LaTeX", Class_LaTeX, "SympyClassBase", {
"add_lowercase": True,
"supports_brackets": True,
"description": "Conversión de expresiones matemáticas a formato LaTeX"
}),
]

View File

@ -20,8 +20,7 @@ m=IP4Mask[23]
IP4Mask[22].to_hex()
IP4[110.1.30.70;255.255.255.0]
n=IP4[110.1.30.70;255.255.255.0]
a=25/51
a*52
latex[x**z/rr]
latex(x**z/rr)

View File

@ -1,6 +1,6 @@
{
"window_geometry": "1020x700+137+49",
"sash_pos_x": 353,
"window_geometry": "1020x700+238+107",
"sash_pos_x": 355,
"symbolic_mode": true,
"show_numeric_approximation": true,
"keep_symbolic_fractions": true,

View File

@ -113,6 +113,8 @@ class HybridEvaluationEngine:
'Matrix': sympy.Matrix,
'det': lambda m: m.det() if hasattr(m, 'det') else sympy.det(m),
'inv': lambda m: m.inv() if hasattr(m, 'inv') else sympy.Matrix(m).inv(),
# Printing
'latex': sympy.latex, # NUEVO: función latex global
# Plotting (será manejado por resultados interactivos)
'plot': self._create_plot_placeholder,
'plot3d': self._create_plot3d_placeholder,
@ -149,9 +151,8 @@ class HybridEvaluationEngine:
def _update_bracket_parser(self):
"""Actualiza el BracketParser con las clases descubiertas"""
try:
discovered_bracket_classes = get_registered_bracket_classes()
# Combinar con clases existentes del parser
self.parser.BRACKET_CLASSES = self.parser.BRACKET_CLASSES.union(discovered_bracket_classes)
# NUEVO: Llamar al método reload para actualizar dinámicamente
self.parser.reload_bracket_classes()
if self.debug:
print(f"🔧 Bracket classes actualizadas: {self.parser.BRACKET_CLASSES}")

View File

@ -21,6 +21,7 @@ class SympyTools:
"cancel": "Cancelar: cancel(expr). Ej: cancel((x**2 + 2*x + 1)/(x+1))",
"apart": "Fracciones parciales: apart(expr). Ej: apart(1/(x*(x+1)))", # Var opcional en apart
"together": "Unir fracciones: together(expr). Ej: together(1/x + 1/y)",
"latex": "Convertir a LaTeX: latex(expr). Ej: latex(x**2 + 1) → x^{2} + 1",
}
@staticmethod

View File

@ -17,8 +17,8 @@ except ImportError:
class BracketParser:
"""Parser que convierte sintaxis con corchetes y detecta ecuaciones contextualmente"""
# Clases base que soportan sintaxis con corchetes (fallback)
DEFAULT_BRACKET_CLASSES = {'IP4', 'Hex', 'Bin', 'Date', 'Dec', 'Chr', 'IP4Mask'}
# Clases de fallback mínimas si falla el registro dinámico
FALLBACK_BRACKET_CLASSES = {'Hex', 'Bin'}
# Operadores de comparación que pueden formar ecuaciones
EQUATION_OPERATORS = {'==', '!=', '<', '<=', '>', '>=', '='}
@ -27,32 +27,52 @@ class BracketParser:
self.debug = False
self.use_type_registry = use_type_registry and TYPE_REGISTRY_AVAILABLE
# Inicializar clases de corchetes
# Inicializar clases de corchetes dinámicamente
self._update_bracket_classes()
def _update_bracket_classes(self):
"""Actualiza las clases que soportan sintaxis con corchetes"""
if self.use_type_registry:
try:
# Obtener clases del registro de tipos
registered_classes = get_registered_bracket_classes()
self.BRACKET_CLASSES = registered_classes.union(self.DEFAULT_BRACKET_CLASSES)
if self.debug:
print(f"🔧 Bracket classes desde registro: {registered_classes}")
print(f"🔧 Total bracket classes: {self.BRACKET_CLASSES}")
def _get_dynamic_bracket_classes(self) -> Set[str]:
"""
Obtiene las clases de corchetes dinámicamente del registro de tipos
NUEVA FUNCIÓN que reemplaza el hardcoding de DEFAULT_BRACKET_CLASSES
"""
if not self.use_type_registry:
return self.FALLBACK_BRACKET_CLASSES.copy()
try:
# Obtener TODAS las clases registradas que soportan corchetes
registered_classes = get_registered_bracket_classes()
except Exception as e:
if self.debug:
print(f"🔧 Clases dinámicas obtenidas del registro: {registered_classes}")
# Si no hay clases registradas, usar fallback
if not registered_classes:
if self.debug:
print(f"⚠️ Error obteniendo clases del registro: {e}")
self.BRACKET_CLASSES = self.DEFAULT_BRACKET_CLASSES.copy()
else:
self.BRACKET_CLASSES = self.DEFAULT_BRACKET_CLASSES.copy()
print("⚠️ No se encontraron clases registradas, usando fallback")
return self.FALLBACK_BRACKET_CLASSES.copy()
return registered_classes
except Exception as e:
if self.debug:
print(f"⚠️ Error obteniendo clases dinámicas: {e}")
return self.FALLBACK_BRACKET_CLASSES.copy()
def _update_bracket_classes(self):
"""
Actualiza las clases que soportan sintaxis con corchetes dinámicamente
MODIFICADO: Ya no usa DEFAULT_BRACKET_CLASSES hardcodeadas
"""
# Obtener clases dinámicamente del registro de tipos
self.BRACKET_CLASSES = self._get_dynamic_bracket_classes()
if self.debug:
print(f"🔧 Bracket classes actualizadas dinámicamente: {self.BRACKET_CLASSES}")
def reload_bracket_classes(self):
"""Recarga las clases de corchetes desde el registro"""
"""Recarga las clases de corchetes desde el registro dinámicamente"""
if self.debug:
print("🔄 Recargando bracket classes...")
print("🔄 Recargando bracket classes dinámicamente...")
self._update_bracket_classes()
def add_bracket_class(self, class_name: str):

View File

@ -116,6 +116,10 @@ class TypeRegistry:
# Registrar en bracket_classes si es apropiado
if category in ['ClassBase', 'SympyClassBase'] or options.get('supports_brackets', False):
self.bracket_classes.add(name)
# NUEVA FUNCIONALIDAD: También agregar versión en minúscula a bracket_classes
if options.get('add_lowercase', True):
self.bracket_classes.add(name.lower())
# Registrar función Helper si existe
if hasattr(class_obj, 'Helper') and callable(class_obj.Helper):