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:
parent
ee24ef2615
commit
449d503213
|
@ -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"
|
||||
}),
|
||||
]
|
|
@ -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)
|
|
@ -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,
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue