tahamajs's picture
download
raw
20.8 kB
"""
Geometry Visualizer
تجسم‌ساز هندسه
This module provides visualization capabilities for geometric problems,
solutions, and proofs.
"""
import os
import logging
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.patches import Circle, Polygon, FancyBboxPatch
from matplotlib.lines import Line2D
import matplotlib.patches as mpatches
from typing import Dict, List, Any, Optional, Tuple
from datetime import datetime
import json
# Set matplotlib to use Persian fonts
plt.rcParams["font.family"] = ["DejaVu Sans", "Arial Unicode MS", "Tahoma"]
logger = logging.getLogger(__name__)
class GeometryVisualizer:
"""
Visualizer for geometric problems and solutions
تجسم‌ساز مسائل و راه‌حل‌های هندسی
"""
def __init__(self, config: Dict[str, Any] = None):
"""
Initialize the geometry visualizer
Args:
config: Visualization configuration
"""
self.config = config or {}
# Visualization settings
self.resolution = self.config.get("diagrams", {}).get("resolution", [1200, 900])
self.dpi = self.config.get("diagrams", {}).get("dpi", 150)
self.style = self.config.get("diagrams", {}).get("style", "professional")
# Colors
self.colors = self.config.get("diagrams", {}).get(
"colors",
{
"points": "#2E86AB",
"lines": "#A23B72",
"circles": "#F18F01",
"triangles": "#C73E1D",
"annotations": "#6C5CE7",
},
)
# Create output directory
self.output_dir = "visualizations"
os.makedirs(self.output_dir, exist_ok=True)
logger.info("Geometry Visualizer initialized")
def create_triangle_diagram(
self,
vertices: List[Tuple[float, float]],
labels: List[str] = None,
angles: List[float] = None,
title: str = "مثلث",
) -> str:
"""
Create a triangle diagram
Args:
vertices: List of triangle vertices (x, y)
labels: Labels for vertices
angles: Angles at each vertex
title: Diagram title
Returns:
Path to saved diagram
"""
try:
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
# Draw triangle
triangle = Polygon(
vertices,
closed=True,
fill=False,
edgecolor=self.colors["triangles"],
linewidth=3,
)
ax.add_patch(triangle)
# Add vertex labels
if labels is None:
labels = ["A", "B", "C"]
for i, (x, y) in enumerate(vertices):
ax.plot(x, y, "o", color=self.colors["points"], markersize=8)
ax.text(
x,
y + 0.2,
labels[i],
fontsize=14,
ha="center",
fontweight="bold",
color=self.colors["annotations"],
)
# Add angle labels
if angles:
for i, angle in enumerate(angles):
x, y = vertices[i]
ax.text(
x - 0.3,
y - 0.3,
f"{angle}°",
fontsize=12,
ha="center",
color=self.colors["annotations"],
)
# Add side length labels
for i in range(3):
x1, y1 = vertices[i]
x2, y2 = vertices[(i + 1) % 3]
mid_x = (x1 + x2) / 2
mid_y = (y1 + y2) / 2
# Calculate side length
length = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
ax.text(
mid_x,
mid_y,
f"{length:.2f}",
fontsize=10,
ha="center",
va="center",
bbox=dict(boxstyle="round,pad=0.3", facecolor="white", alpha=0.8),
)
# Set up the plot
ax.set_xlim(
min(x for x, y in vertices) - 1, max(x for x, y in vertices) + 1
)
ax.set_ylim(
min(y for x, y in vertices) - 1, max(y for x, y in vertices) + 1
)
ax.set_aspect("equal")
ax.grid(True, alpha=0.3)
ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
# Save the diagram
filename = f"triangle_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Triangle diagram saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating triangle diagram: {e}")
return ""
def create_circle_diagram(
self,
center: Tuple[float, float],
radius: float,
points: List[Tuple[float, float]] = None,
chords: List[List[Tuple[float, float]]] = None,
tangents: List[List[Tuple[float, float]]] = None,
title: str = "دایره",
) -> str:
"""
Create a circle diagram
Args:
center: Circle center (x, y)
radius: Circle radius
points: Points on the circle
chords: List of chords
tangents: List of tangent lines
title: Diagram title
Returns:
Path to saved diagram
"""
try:
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
# Draw circle
circle = Circle(
center,
radius,
fill=False,
edgecolor=self.colors["circles"],
linewidth=3,
)
ax.add_patch(circle)
# Draw center point
ax.plot(
center[0],
center[1],
"o",
color=self.colors["points"],
markersize=8,
label="مرکز",
)
# Draw points on circle
if points:
for i, (x, y) in enumerate(points):
ax.plot(x, y, "o", color=self.colors["points"], markersize=6)
ax.text(
x + 0.2,
y + 0.2,
f"P{i+1}",
fontsize=10,
ha="center",
color=self.colors["annotations"],
)
# Draw chords
if chords:
for chord in chords:
if len(chord) == 2:
x_coords = [chord[0][0], chord[1][0]]
y_coords = [chord[0][1], chord[1][1]]
ax.plot(
x_coords,
y_coords,
color=self.colors["lines"],
linewidth=2,
linestyle="--",
)
# Draw tangents
if tangents:
for tangent in tangents:
if len(tangent) == 2:
x_coords = [tangent[0][0], tangent[1][0]]
y_coords = [tangent[0][1], tangent[1][1]]
ax.plot(
x_coords,
y_coords,
color=self.colors["lines"],
linewidth=2,
linestyle="-",
)
# Set up the plot
ax.set_xlim(center[0] - radius - 1, center[0] + radius + 1)
ax.set_ylim(center[1] - radius - 1, center[1] + radius + 1)
ax.set_aspect("equal")
ax.grid(True, alpha=0.3)
ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
ax.legend()
# Save the diagram
filename = f"circle_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Circle diagram saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating circle diagram: {e}")
return ""
def create_polygon_diagram(
self,
vertices: List[Tuple[float, float]],
polygon_type: str = "polygon",
labels: List[str] = None,
title: str = "چندضلعی",
) -> str:
"""
Create a polygon diagram
Args:
vertices: List of polygon vertices
polygon_type: Type of polygon
labels: Labels for vertices
title: Diagram title
Returns:
Path to saved diagram
"""
try:
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
# Draw polygon
polygon = Polygon(
vertices,
closed=True,
fill=False,
edgecolor=self.colors["triangles"],
linewidth=3,
)
ax.add_patch(polygon)
# Add vertex labels
if labels is None:
labels = [chr(65 + i) for i in range(len(vertices))]
for i, (x, y) in enumerate(vertices):
ax.plot(x, y, "o", color=self.colors["points"], markersize=8)
ax.text(
x,
y + 0.2,
labels[i],
fontsize=14,
ha="center",
fontweight="bold",
color=self.colors["annotations"],
)
# Set up the plot
ax.set_xlim(
min(x for x, y in vertices) - 1, max(x for x, y in vertices) + 1
)
ax.set_ylim(
min(y for x, y in vertices) - 1, max(y for x, y in vertices) + 1
)
ax.set_aspect("equal")
ax.grid(True, alpha=0.3)
ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
# Save the diagram
filename = f"{polygon_type}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Polygon diagram saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating polygon diagram: {e}")
return ""
def create_proof_visualization(
self, steps: List[Dict[str, Any]], title: str = "تجسم اثبات"
) -> str:
"""
Create a visualization of proof steps
Args:
steps: List of proof steps
title: Visualization title
Returns:
Path to saved visualization
"""
try:
fig, ax = plt.subplots(1, 1, figsize=(12, 8))
# Create a text-based visualization
y_pos = 0.9
step_height = 0.1
for i, step in enumerate(steps):
step_text = f"مرحله {i+1}: {step.get('description', '')}"
# Add step text
ax.text(
0.05,
y_pos,
step_text,
fontsize=12,
ha="left",
va="top",
transform=ax.transAxes,
bbox=dict(
boxstyle="round,pad=0.5", facecolor="lightblue", alpha=0.7
),
)
# Add result if available
if "result" in step:
result_text = f"نتیجه: {step['result'][:100]}..."
ax.text(
0.05,
y_pos - 0.03,
result_text,
fontsize=10,
ha="left",
va="top",
transform=ax.transAxes,
style="italic",
color="darkgreen",
)
y_pos -= step_height
# Set up the plot
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis("off")
ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
# Save the visualization
filename = f"proof_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Proof visualization saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating proof visualization: {e}")
return ""
def create_comparison_chart(
self, results: Dict[str, Any], title: str = "مقایسه نتایج"
) -> str:
"""
Create a comparison chart of different solving methods
Args:
results: Results from different methods
title: Chart title
Returns:
Path to saved chart
"""
try:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# Extract data
methods = []
confidences = []
solution_lengths = []
for method, result in results.items():
if method == "comparison":
continue
if "error" not in result:
methods.append(method)
confidences.append(result.get("confidence", 0))
solution_lengths.append(len(result.get("solution", "")))
# Confidence chart
if methods:
bars1 = ax1.bar(
methods, confidences, color=self.colors["points"], alpha=0.7
)
ax1.set_title("امتیاز اعتماد", fontsize=14, fontweight="bold")
ax1.set_ylabel("اعتماد", fontsize=12)
ax1.set_ylim(0, 1)
# Add value labels on bars
for bar, value in zip(bars1, confidences):
ax1.text(
bar.get_x() + bar.get_width() / 2,
bar.get_height() + 0.01,
f"{value:.2f}",
ha="center",
va="bottom",
fontsize=10,
)
# Solution length chart
bars2 = ax2.bar(
methods, solution_lengths, color=self.colors["lines"], alpha=0.7
)
ax2.set_title("طول راه‌حل", fontsize=14, fontweight="bold")
ax2.set_ylabel("تعداد کاراکتر", fontsize=12)
# Add value labels on bars
for bar, value in zip(bars2, solution_lengths):
ax2.text(
bar.get_x() + bar.get_width() / 2,
bar.get_height() + max(solution_lengths) * 0.01,
f"{value}",
ha="center",
va="bottom",
fontsize=10,
)
# Set up the plot
fig.suptitle(title, fontsize=16, fontweight="bold")
plt.tight_layout()
# Save the chart
filename = f"comparison_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Comparison chart saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating comparison chart: {e}")
return ""
def create_workflow_diagram(
self, workflow_steps: List[Dict[str, Any]], title: str = "گردش کار حل مسئله"
) -> str:
"""
Create a workflow diagram
Args:
workflow_steps: List of workflow steps
title: Diagram title
Returns:
Path to saved diagram
"""
try:
fig, ax = plt.subplots(1, 1, figsize=(12, 8))
# Create flowchart-style visualization
y_pos = 0.9
step_height = 0.12
for i, step in enumerate(workflow_steps):
step_name = step.get("step", f"مرحله {i+1}")
step_desc = step.get("description", "")
# Create rounded rectangle for each step
rect = FancyBboxPatch(
(0.1, y_pos - 0.05),
0.8,
0.08,
boxstyle="round,pad=0.02",
facecolor="lightblue",
edgecolor="navy",
linewidth=2,
)
ax.add_patch(rect)
# Add step text
ax.text(
0.5,
y_pos,
f"{step_name}: {step_desc}",
fontsize=11,
ha="center",
va="center",
transform=ax.transAxes,
fontweight="bold",
)
# Add arrow to next step
if i < len(workflow_steps) - 1:
ax.arrow(
0.5,
y_pos - 0.05,
0,
-0.02,
head_width=0.02,
head_length=0.01,
fc="black",
ec="black",
transform=ax.transAxes,
)
y_pos -= step_height
# Set up the plot
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis("off")
ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
# Save the diagram
filename = f"workflow_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
plt.savefig(filepath, dpi=self.dpi, bbox_inches="tight")
plt.close()
logger.info(f"Workflow diagram saved to {filepath}")
return filepath
except Exception as e:
logger.error(f"Error creating workflow diagram: {e}")
return ""
def get_visualization_info(self) -> Dict[str, Any]:
"""
Get information about the visualizer
Returns:
Dictionary containing visualizer information
"""
return {
"output_directory": self.output_dir,
"resolution": self.resolution,
"dpi": self.dpi,
"style": self.style,
"colors": self.colors,
"available_diagrams": [
"triangle_diagram",
"circle_diagram",
"polygon_diagram",
"proof_visualization",
"comparison_chart",
"workflow_diagram",
],
}
def cleanup_old_files(self, days_old: int = 7):
"""
Clean up old visualization files
Args:
days_old: Number of days old files to remove
"""
try:
import time
current_time = time.time()
cutoff_time = current_time - (days_old * 24 * 60 * 60)
removed_count = 0
for filename in os.listdir(self.output_dir):
filepath = os.path.join(self.output_dir, filename)
if os.path.isfile(filepath):
file_time = os.path.getmtime(filepath)
if file_time < cutoff_time:
os.remove(filepath)
removed_count += 1
logger.info(f"Cleaned up {removed_count} old visualization files")
except Exception as e:
logger.error(f"Error cleaning up old files: {e}")

Xet Storage Details

Size:
20.8 kB
·
Xet hash:
e2c49c62a3882052cb56cfef3b556f9366ad0a9d115bad66fbb826c950ae9759

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.