Shakeel1979's picture
Update app.py
365203d verified
Raw History Blame Contribute Delete
17.2 kB
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon, Circle
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from functools import lru_cache
from io import BytesIO
# Cached functions for efficiency
@lru_cache(maxsize=128)
def calculate_distance(x1, y1, x2, y2):
return np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
@lru_cache(maxsize=128)
def calculate_angle(a, b, c):
cos_angle = (b ** 2 + c ** 2 - a ** 2) / (2 * b * c)
cos_angle = np.clip(cos_angle, -1.0, 1.0)
return np.degrees(np.arccos(cos_angle))
@lru_cache(maxsize=128)
def is_valid_triangle(a, b, c):
return a + b > c and b + c > a and c + a > b
@lru_cache(maxsize=128)
def calculate_area(a, b, c):
s = (a + b + c) / 2
return np.sqrt(max(0, s * (s - a) * (s - b) * (s - c)))
def calculate_triangle_properties(x1, y1, x2, y2, x3, y3):
a = calculate_distance(x2, y2, x3, y3)
b = calculate_distance(x1, y1, x3, y3)
c = calculate_distance(x1, y1, x2, y2)
if not is_valid_triangle(a, b, c):
st.error("The entered points do not form a valid triangle. Please enter the coordinates again.")
return None
area = calculate_area(a, b, c)
perimeter = a + b + c
s = perimeter / 2
A = calculate_angle(a, b, c)
B = calculate_angle(b, a, c)
C = calculate_angle(c, a, b)
G_x, G_y = (x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3 # Centroid
I_x = (a * x1 + b * x2 + c * x3) / perimeter
I_y = (a * y1 + b * y2 + c * y3) / perimeter
D = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))
U_x = ((x1**2 + y1**2) * (y2 - y3) + (x2**2 + y2**2) * (y3 - y1) + (x3**2 + y3**2) * (y1 - y2)) / D
U_y = ((x1**2 + y1**2) * (x3 - x2) + (x2**2 + y2**2) * (x1 - x3) + (x3**2 + y3**2) * (x2 - x1)) / D
radius_in = area / s
radius_circum = (a * b * c) / (4 * area)
midpoints = (
((x1 + x2) / 2, (y1 + y2) / 2),
((x2 + x3) / 2, (y2 + y3) / 2),
((x3 + x1) / 2, (y3 + y1) / 2)
)
return {
'sides': (a, b, c),
'angles': (A, B, C),
'area': area,
'perimeter': perimeter,
'centroid': (G_x, G_y),
'incenter': (I_x, I_y),
'circumcenter': (U_x, U_y),
'radius_in': radius_in,
'radius_circum': radius_circum,
'midpoints': midpoints
}
def plot_triangle(vertices, properties):
fig, ax = plt.subplots(figsize=(18, 12))
(x1, y1), (x2, y2), (x3, y3) = vertices
a, b, c = properties['sides']
A, B, C = properties['angles']
I_x, I_y = properties['incenter']
U_x, U_y = properties['circumcenter']
G_x, G_y = properties['centroid']
midpoints = properties['midpoints']
radius_in = properties['radius_in']
radius_circum = properties['radius_circum']
perimeter = properties['perimeter']
area = properties['area']
triangle = Polygon(vertices, closed=True, edgecolor='b', facecolor='lightblue', linewidth=2)
ax.add_patch(triangle)
vertex_labels = [f"Vertex A ({x1:.1f}, {y1:.1f})", f"Vertex B ({x2:.1f}, {y2:.1f})", f"Vertex C ({x3:.1f}, {y3:.1f})"]
vertex_name = ["A", "B", "C"]
for i, (vx, vy) in enumerate(vertices):
ax.scatter(vx, vy, color='blue', zorder=3)
ax.text(vx+0.01*G_x, vy+0.02*G_y, vertex_name[i], fontsize=10, ha="left", va="bottom", color='blue')
key_points = [
(G_x, G_y, 'green', f"Centroid ({G_x:.1f}, {G_y:.1f})"),
(I_x, I_y, 'red', f"Incenter ({I_x:.1f}, {I_y:.1f})"),
(U_x, U_y, 'black', f"Circumcenter ({U_x:.1f}, {U_y:.1f})")
]
for x, y, color, label in key_points:
ax.scatter(x, y, color=color, zorder=5)
mid_points = [
(midpoints[0], 'orange', f"Mid-point M1 ({midpoints[0][0]:.1f}, {midpoints[0][1]:.1f})"),
(midpoints[1], 'orange', f"Mid-point M2 ({midpoints[1][0]:.1f}, {midpoints[1][1]:.1f})"),
(midpoints[2], 'orange', f"Mid-point M3 ({midpoints[2][0]:.1f}, {midpoints[2][1]:.1f})")
]
for i, (midpoint, color, label) in enumerate(mid_points):
mx, my = midpoint
ax.scatter(mx, my, color=color, zorder=3)
ax.text(mx + 0.01 * G_x, my + 0.02 * G_y, f"M{i}", fontsize=10, ha="left", va="bottom", color=color)
incircle = Circle((I_x, I_y), radius_in, color='red', fill=False, linestyle='--', linewidth=1)
circumcircle = Circle((U_x, U_y), radius_circum, color='black', fill=False, linestyle='--', linewidth=1)
ax.add_patch(incircle)
ax.add_patch(circumcircle)
handles = [
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='blue', markersize=7, label=label)
for label in vertex_labels
]
handles.extend([
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=color, markersize=7, label=label)
for _, color, label in mid_points
])
handles.extend([
plt.Line2D([0], [0], marker='<', color='blue', markersize=7, linestyle='none', label=f"Angle {angle}: {value:.1f}Β°")
for angle, value in zip(['A', 'B', 'C'], [A, B, C])
])
handles.extend([
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=color, markersize=7, label=label)
for _, _, color, label in key_points
])
handles.extend([
plt.Line2D([0], [0], linestyle='-', color='blue', markersize=6, label=f"Side {side}: {length:.1f}")
for side, length in zip(['a = BC', 'b = AC', 'c = AB'], [a, b, c])
])
handles.extend([
plt.Line2D([0], [0], marker='o', markerfacecolor='white', markeredgecolor='red', markersize=5, linestyle='none', label=f"Incircle radius: {radius_in:.1f}"),
plt.Line2D([0], [0], marker='o', markerfacecolor='white', markeredgecolor='black', markersize=8, linestyle='none', label=f"Circumcircle radius: {radius_circum:.1f}")
])
handles.extend([
plt.Line2D([0], [0], marker='^', markerfacecolor='white', markeredgecolor='blue', markersize=7, linestyle='none', label=f"Perimeter: {perimeter:.1f}"),
plt.Line2D([0], [0], marker='^', markerfacecolor='lightblue', markeredgecolor='lightblue', markersize=7, linestyle='none', label=f"Area: {area:.1f}")
])
ax.legend(handles=handles, loc='upper left', fontsize=8)
padding = 5
ax.set_xlim([min(x1, x2, x3) - padding, max(x1, x2, x3) + padding])
ax.set_ylim([min(y1, y2, y3) - padding, max(y1, y2, y3) + padding])
ax.set_aspect('equal', adjustable='datalim')
ax.set_title('Triangle Visualization', fontsize=23)
ax.set_xlabel('X-axis', fontsize=12)
ax.set_ylabel('Y-axis', fontsize=12)
plt.grid(color='gray', linestyle='--', linewidth=0.5, alpha=0.5)
st.pyplot(fig)
return fig
def save_as_pdf_reportlab(x1, y1, x2, y2, x3, y3, a, b, c, A, B, C, area, perimeter,
I_x, I_y, U_x, U_y, G_x, G_y, midpoints, radius_in, radius_circum, fig):
fig.savefig("triangle_plot.png")
canvas_obj = canvas.Canvas("Triangle_solver_results.pdf", pagesize=letter)
width, height = letter
canvas_obj.setFont("Helvetica", 16)
canvas_obj.drawString(100, height - 40, "Triangle Solver Results")
canvas_obj.setFont("Helvetica", 12)
canvas_obj.drawString(30, height - 60, "Coordinates of Triangle:")
canvas_obj.drawString(50, height - 75, f"Vertex A: ({x1:.3f}, {y1:.3f})")
canvas_obj.drawString(50, height - 90, f"Vertex B: ({x2:.3f}, {y2:.3f})")
canvas_obj.drawString(50, height - 105, f"Vertex C: ({x3:.3f}, {y3:.3f})")
canvas_obj.drawString(30, height - 130, "Mid-Points of Triangle:")
canvas_obj.drawString(50, height - 145, f"Midpoint of AB: ({midpoints[0][0]:.3f}, {midpoints[0][1]:.3f})")
canvas_obj.drawString(50, height - 160, f"Midpoint of BC: ({midpoints[1][0]:.3f}, {midpoints[1][1]:.3f})")
canvas_obj.drawString(50, height - 175, f"Midpoint of AC: ({midpoints[2][0]:.3f}, {midpoints[2][1]:.3f})")
canvas_obj.drawString(30, height - 200, "Angles of Triangle:")
canvas_obj.drawString(50, height - 215, f"Angle A: {A:.3f}Β°")
canvas_obj.drawString(50, height - 230, f"Angle B: {B:.3f}Β°")
canvas_obj.drawString(50, height - 245, f"Angle C: {C:.3f}Β°")
canvas_obj.drawString(30, height - 270, "Sides of Triangle:")
canvas_obj.drawString(50, height - 285, f"Side a = BC: {a:.3f} units")
canvas_obj.drawString(50, height - 300, f"Side b = AC: {b:.3f} units")
canvas_obj.drawString(50, height - 315, f"Side c = AB: {c:.3f} units")
canvas_obj.drawString(30, height - 340, "Other Properties:")
canvas_obj.drawString(50, height - 355, f"Centroid: ({G_x:.3f}, {G_y:.3f})")
canvas_obj.drawString(50, height - 370, f"Perimeter: {perimeter:.3f} units")
canvas_obj.drawString(50, height - 385, f"Area: {area:.3f} square units")
canvas_obj.drawString(30, height - 410, "Incenter of Triangle:")
canvas_obj.drawString(50, height - 425, f"Coordinates: ({I_x:.3f}, {I_y:.3f})")
canvas_obj.drawString(50, height - 440, f"Radius: {radius_in:.3f} units")
canvas_obj.drawString(30, height - 465, "Circumcenter of Triangle:")
canvas_obj.drawString(50, height - 480, f"Coordinates: ({U_x:.3f}, {U_y:.3f})")
canvas_obj.drawString(50, height - 495, f"Radius: {radius_circum:.3f} units")
canvas_obj.drawImage("triangle_plot.png", 30, height - 650, width=500, height=300)
canvas_obj.save()
return
def main():
st.markdown("""
<h1 style='text-align: left;'>
<span style="display: inline-block; transform: scaleX(-1);">β—­</span> Advanced Triangle Solver β—­
</h1> """, unsafe_allow_html=True)
def get_coordinate_inputs():
st.sidebar.header("Enter the cartesian coordinates for the three points of a triangle:")
coordinates = {}
for point, label in [('1', 'A'), ('2', 'B'), ('3', 'C')]:
cols = st.sidebar.columns([3, 3])
coordinates[f'x{point}'] = cols[0].number_input(
f"X{point}", value=0.0, min_value=-100.0, max_value=100.0, step=0.001, format="%.3f"
)
coordinates[f'y{point}'] = cols[1].number_input(
f"Y{point}", value=0.0, min_value=-100.0, max_value=100.0, step=0.001, format="%.3f"
)
return coordinates
coords = get_coordinate_inputs()
st.sidebar.markdown("<br>", unsafe_allow_html=True)
button_col = st.sidebar.columns([1, 2, 1])
if not button_col[1].button("Solve Triangle"):
return
properties = calculate_triangle_properties(
coords['x1'], coords['y1'],
coords['x2'], coords['y2'],
coords['x3'], coords['y3']
)
if properties is None:
return
a, b, c = properties['sides']
A, B, C = properties['angles']
area = properties['area']
perimeter = properties['perimeter']
G_x, G_y = properties['centroid']
I_x, I_y = properties['incenter']
U_x, U_y = properties['circumcenter']
radius_in = properties['radius_in']
radius_circum = properties['radius_circum']
midpoints = properties['midpoints']
vertices = [(coords['x1'], coords['y1']),
(coords['x2'], coords['y2']),
(coords['x3'], coords['y3'])]
st.success("The entered points form a valid triangle.")
def display_coordinates():
col1, col2 = st.columns(2)
with col1:
st.subheader("Coordinates of Triangle:")
for i, vertex in enumerate(['A', 'B', 'C']):
st.markdown(f"Vertex {vertex}: **({vertices[i][0]:.3f}, {vertices[i][1]:.3f})**")
with col2:
st.subheader("Mid-Points of Triangle:")
for i, points in enumerate([('A','B'), ('B','C'), ('A','C')]):
st.markdown(f"Midpoint of {points[0]}{points[1]}: **({midpoints[i][0]:.3f}, {midpoints[i][1]:.3f})**")
def display_measurements():
col1, col2 = st.columns(2)
with col1:
st.subheader("Angles of Triangle:")
for angle, value in zip(['A', 'B', 'C'], [A, B, C]):
st.markdown(f"Angle {angle}: **{value:.3f}Β°**")
with col2:
st.subheader("Sides of Triangle:")
for side, value in zip(['a = BC', 'b = AC', 'c = AB'], [a, b, c]):
st.markdown(f"Side {side}: **{value:.3f}** units")
def display_centers():
col1, col2 = st.columns(2)
with col1:
st.subheader("Incenter of Triangle:")
st.markdown(f"Coordinates: **({I_x:.3f}, {I_y:.3f})**")
st.markdown(f"Radius: **{radius_in:.3f}** units")
with col2:
st.subheader("Circumcenter of Triangle:")
st.markdown(f"Coordinates: **({U_x:.3f}, {U_y:.3f})**")
st.markdown(f"Radius: **{radius_circum:.3f}** units")
def display_other_properties():
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.subheader("Other Properties:")
st.markdown(f"Centroid: **({G_x:.3f}, {G_y:.3f})**")
st.markdown(f"Perimeter: **{perimeter:.3f}** units")
st.markdown(f"Area: **{area:.3f}** square units")
display_coordinates()
display_measurements()
display_centers()
display_other_properties()
# Plot triangle
fig = plot_triangle(vertices, properties)
### Code for Save as PDF
# Generate PDF and get the data
save_as_pdf_reportlab(
coords['x1'], coords['y1'], coords['x2'], coords['y2'], coords['x3'], coords['y3'],
a, b, c, A, B, C, area, perimeter, I_x, I_y, U_x, U_y, G_x, G_y,
midpoints, radius_in, radius_circum, fig)
# Read the saved PDF file
with open("Triangle_solver_results.pdf", "rb") as pdf_file:
pdf_data = pdf_file.read()
# Download button
st.download_button("Download PDF", pdf_data,
file_name="Triangle_solver_results.pdf",
mime="application/pdf")
## Old code for Save as PDF
# if st.button("Save as PDF"):
# save_as_pdf_reportlab(
# coords['x1'], coords['y1'], coords['x2'], coords['y2'], coords['x3'], coords['y3'],
# a, b, c, A, B, C, area, perimeter, I_x, I_y, U_x, U_y, G_x, G_y,
# midpoints, radius_in, radius_circum, fig
# )
# st.success("Results saved as PDF!")
# with open("Triangle_solver_results.pdf", "rb") as pdf_file:
# st.download_button("Download PDF", pdf_file, file_name="Triangle_solver_results.pdf")
### New code for Save as PDF
# if st.button("Save as PDF"):
# try:
# # Add debug message
# st.info("Creating PDF... Please wait")
# # Call your PDF creation function
# save_as_pdf_reportlab(
# coords['x1'], coords['y1'], coords['x2'], coords['y2'], coords['x3'], coords['y3'],
# a, b, c, A, B, C, area, perimeter, I_x, I_y, U_x, U_y, G_x, G_y,
# midpoints, radius_in, radius_circum, fig
# )
# # Check if file exists and has content
# pdf_path = "Triangle_solver_results.pdf"
# if os.path.exists(pdf_path) and os.path.getsize(pdf_path) > 0:
# st.success("PDF created successfully!")
# # Read the PDF file
# with open(pdf_path, "rb") as pdf_file:
# pdf_data = pdf_file.read()
# # Create download button
# st.download_button(
# label="πŸ“„ Download PDF",
# data=pdf_data,
# file_name="Triangle_solver_results.pdf",
# mime="application/pdf"
# )
# else:
# st.error("❌ PDF file was not created or is empty!")
# st.info("Check if the save_as_pdf_reportlab function is working correctly")
# except FileNotFoundError as e:
# st.error(f"❌ File not found: {e}")
# except PermissionError as e:
# st.error(f"❌ Permission denied: {e}")
# except Exception as e:
# st.error(f"❌ Error creating PDF: {str(e)}")
# st.info("Please check your save_as_pdf_reportlab function for errors")
# # Alternative: Test if your PDF function works at all
# if st.button("πŸ” Debug PDF Function"):
# try:
# st.info("Testing PDF creation...")
# # Test with minimal parameters
# save_as_pdf_reportlab(
# coords['x1'], coords['y1'], coords['x2'], coords['y2'], coords['x3'], coords['y3'],
# a, b, c, A, B, C, area, perimeter, I_x, I_y, U_x, U_y, G_x, G_y,
# midpoints, radius_in, radius_circum, fig
# )
# st.success("PDF function executed without errors")
# except Exception as e:
# st.error(f"PDF function failed: {str(e)}")
# st.code(str(e)) # Show detailed error
if __name__ == "__main__":
main()