Spaces:
Build error
Build error
File size: 15,980 Bytes
6372af3 d5acdc1 360cc19 6372af3 d5acdc1 6372af3 9d36ff7 d5acdc1 9d36ff7 6372af3 2aa8a14 6372af3 388dedf 9d36ff7 388dedf 9d36ff7 6372af3 388dedf 9d36ff7 388dedf 9d36ff7 6372af3 388dedf 9d36ff7 6372af3 388dedf 1745bbb 388dedf 1745bbb 6372af3 9d36ff7 6372af3 0bd62ab 6372af3 168dae3 2c1bf78 c05f8a9 14afed2 168dae3 23c3e38 9d36ff7 168dae3 23c3e38 168dae3 0a90659 e71e4e1 32e4e2e 0a90659 6ba59ad e312bc0 9d36ff7 168dae3 0a90659 9d36ff7 1745bbb 9d36ff7 0a90659 e71e4e1 a249c25 9d36ff7 e71e4e1 9d36ff7 e71e4e1 32e4e2e e71e4e1 e312bc0 32e4e2e ce87c5c 1745bbb 1a6449a ce87c5c 1745bbb 1a6449a ce87c5c a4c9092 3d9fb08 544121c 3d9fb08 a4c9092 683f81a 3d9fb08 683f81a d70e9fb e312bc0 3d9fb08 a4c9092 3d9fb08 a4c9092 d55fa25 f69cb08 d55fa25 0bd62ab d55fa25 6372af3 9d36ff7 6372af3 7d38b03 51f5ca0 7d38b03 1604b39 869830c 1a6449a 869830c 3d9fb08 1a6449a 544121c 3d9fb08 1a6449a 544121c 3d9fb08 1a6449a 3d9fb08 6372af3 3d9fb08 869830c 6372af3 9d36ff7 869830c 6372af3 9d36ff7 869830c 6372af3 869830c 6372af3 77b8003 6372af3 9d36ff7 869830c cb88584 869830c 78598a6 3d9fb08 78598a6 869830c cb88584 869830c f6669c3 869830c cb88584 78598a6 f6669c3 78598a6 cb88584 18ca239 6372af3 869830c 6372af3 869830c 6372af3 869830c 77b8003 6372af3 d55fa25 8385c0f d55fa25 6372af3 9d36ff7 2c1bf78 6372af3 168dae3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon, Circle
# Function to calculate the distance between two points
def calculate_distance(x1, y1, x2, y2):
return np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
# Function to calculate angles using the Law of Cosines
def calculate_angle(a, b, c):
try:
angle = np.degrees(np.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)))
except ValueError:
angle = 0 # Handle possible domain error in acos
return angle
# Function to calculate area using Heron's formula
def calculate_area(a, b, c):
s = (a + b + c) / 2
area = np.sqrt(s * (s - a) * (s - b) * (s - c))
return area
# Function to calculate the perimeter
def calculate_perimeter(a, b, c):
return a + b + c
# Function to calculate the radius of the inscribed circle
def calculate_radius_inscribed_circle(a, b, c):
try:
s = (a + b + c) / 2
area = calculate_area(a, b, c)
radius = area / s
except ZeroDivisionError:
radius = 0 # Handle case where area or perimeter is zero
return radius
# Function to calculate the radius of the circumscribed circle
def calculate_radius_circumscribed_circle(a, b, c):
try:
area = calculate_area(a, b, c)
radius = (a * b * c) / (4 * area)
except ZeroDivisionError:
radius = 0 # Handle case where area is zero
return radius
# Function to calculate the centroid coordinates
def calculate_centroid(x1, y1, x2, y2, x3, y3):
G_x = (x1 + x2 + x3) / 3
G_y = (y1 + y2 + y3) / 3
return G_x, G_y
# Function to calculate the incenter coordinates
def calculate_incenter(x1, y1, x2, y2, x3, y3, a, b, c):
try:
I_x = (a * x1 + b * x2 + c * x3) / (a + b + c)
I_y = (a * y1 + b * y2 + c * y3) / (a + b + c)
except ZeroDivisionError:
I_x, I_y = 0, 0 # Handle division by zero if sides sum to zero
return I_x, I_y
# Function to calculate the circumcenter coordinates
def calculate_circumcenter(x1, y1, x2, y2, x3, y3, a, b, c):
try:
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
except ZeroDivisionError:
U_x, U_y = 0, 0 # Handle division by zero in circumcenter calculation
return U_x, U_y
# Function to calculate midpoints of sides
def calculate_midpoints(x1, y1, x2, y2, x3, y3):
# Midpoint of AB
M1_x = (x1 + x2) / 2
M1_y = (y1 + y2) / 2
# Midpoint of BC
M2_x = (x2 + x3) / 2
M2_y = (y2 + y3) / 2
# Midpoint of CA
M3_x = (x3 + x1) / 2
M3_y = (y3 + y1) / 2
return (M1_x, M1_y), (M2_x, M2_y), (M3_x, M3_y)
# Function to format values close to zero as 0
def format_zero(val):
if abs(val) < 1e-4:
return 0.0
return val
# Function to plot the triangle with all points in different colors and a legend
def plot_triangle(x1, y1, x2, y2, x3, y3, I_x, I_y, U_x, U_y, G_x, G_y, midpoints, a, b, c):
fig, ax = plt.subplots(figsize=(10, 8))
triangle = Polygon([(x1, y1), (x2, y2), (x3, y3)], closed=True, edgecolor='b', facecolor='lightblue', linewidth=2)
ax.add_patch(triangle)
# Define colors for different points
vertex_color = 'blue'
midpoint_color = 'green'
centroid_color = 'orange'
incenter_color = 'red'
circumcenter_color = 'purple'
# Plot the triangle vertices
vertices = [(x1, y1), (x2, y2), (x3, y3)]
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=vertex_color, zorder=3)
ax.text(vx+0.01*G_x, vy+0.02*G_y, vertex_name[i], fontsize=10, ha="left", va="bottom", color=vertex_color)
# Plot key points with their corresponding colors
key_points = [
(I_x, I_y, incenter_color),
(U_x, U_y, circumcenter_color),
(G_x, G_y, centroid_color)
]
key_points_labels = [f"Incenter ({I_x:.1f}, {I_y:.1f})", f"Circumcenter ({U_x:.1f}, {U_y:.1f})", f"Centroid ({G_x:.1f}, {G_y:.1f})"]
for x, y, color in key_points:
ax.scatter(x, y, color=color, zorder=5)
# Plot midpoints of sides
midpoints_labels = [f"Mid-Point M1 ({(x1 + x2) / 2:.1f}, {(y1 + y2) / 2:.1f})",
f"Mid-Point M2 ({(x2 + x3) / 2:.1f}, {(y2 + y3) / 2:.1f})",
f"Mid-Point M3 ({(x1 + x3) / 2:.1f}, {(y1 + y3) / 2:.1f})"]
midpoint_name = ["M1", "M2", "M3"]
for i, (mx, my) in enumerate(midpoints):
ax.scatter(mx, my, color=midpoint_color, zorder=3)
ax.text(mx+0.01*G_x, my+0.02*G_y, midpoint_name[i], fontsize=10, ha="left", va="bottom", color=midpoint_color)
# Draw the inscribed circle (incircle)
radius_in = calculate_radius_inscribed_circle(a, b, c)
incircle = Circle((I_x, I_y), radius_in, color=incenter_color, fill=False, linestyle='--', linewidth=1, label="Inscribed Circle")
ax.add_patch(incircle)
# Draw the circumscribed circle (circumcircle)
radius_circum = calculate_radius_circumscribed_circle(a, b, c)
circumcircle = Circle((U_x, U_y), radius_circum, color=circumcenter_color, fill=False, linestyle='--', linewidth=1, label="Circumscribed Circle")
ax.add_patch(circumcircle)
# Calculate area and perimeter of triangle
area = calculate_area(a, b, c)
perimeter = calculate_perimeter(a, b, c)
# Calculate the lengths of the sides of the triangle using Euclidean distance
a = calculate_distance(x2, y2, x3, y3)
b = calculate_distance(x1, y1, x3, y3)
c = calculate_distance(x1, y1, x2, y2)
sides = [f"Side a: {a:.1f}", f"Side b: {b:.1f}", f"Side c: {c:.1f}"]
# Validate if it's a valid triangle
if not is_valid_triangle(a, b, c):
st.error("The entered points do not form a valid triangle.")
return
# Calculate angles using the Law of Cosines
A = calculate_angle(a, b, c)
B = calculate_angle(b, a, c)
C = calculate_angle(c, a, b)
vertex_angles = [f"A: {A:.1f}°", f"B: {B:.1f}°", f"C: {C:.1f}°"]
# Check if angles sum up to 180 degrees
if abs(A + B + C - 180) > 1e-2:
st.error("The sum of the angles is not 180 degrees.")
return
# Add legend
handles = [
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_labels[0]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_labels[1]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_labels[2]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=midpoint_color, markersize=7, label=midpoints_labels[0]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=midpoint_color, markersize=7, label=midpoints_labels[1]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=midpoint_color, markersize=7, label=midpoints_labels[2]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_angles[0]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_angles[1]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=vertex_color, markersize=7, label=vertex_angles[2]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=incenter_color, markersize=7, label=key_points_labels[0]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=circumcenter_color, markersize=7, label=key_points_labels[1]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=centroid_color, markersize=7, label=key_points_labels[2]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor="blue", markersize=7, label=sides[0]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor="blue", markersize=7, label=sides[1]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor="blue", markersize=7, label=sides[2]),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor="lightblue", markersize=7, label=f"Area: {area:.1f}"),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor="blue", markersize=7, label=f"Perimeter: {perimeter:.1f}"),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=incenter_color, markersize=7, label=f"Incircle radius: {radius_in:.1f}"),
plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=circumcenter_color, markersize=7, label=f"Circumcircle radius: {radius_circum:.1f}")
]
ax.legend(handles=handles, loc='upper left', fontsize=8)
# Adjust the plot limits and aspect ratio
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)
# Add a light grid
plt.grid(color='gray', linestyle='--', linewidth=0.5, alpha=0.5)
st.pyplot(fig)
# Function to check if the sides form a valid triangle
def is_valid_triangle(a, b, c):
# Check if the sum of two sides is greater than the third side (Triangle Inequality Theorem)
return a + b > c and b + c > a and c + a > b
# Main function to interact with the user
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)
st.sidebar.header("Enter the cartesian coordinates for the three points of a triangle:")
# # Coordinates input (X1, Y1), (X2, Y2), (X3, Y3)
# x1 = st.sidebar.number_input("X1", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# y1 = st.sidebar.number_input("Y1", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# x2 = st.sidebar.number_input("X2", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# y2 = st.sidebar.number_input("Y2", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# x3 = st.sidebar.number_input("X3", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# y3 = st.sidebar.number_input("Y3", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# Coordinates input (X1, Y1), (X2, Y2), (X3, Y3)
col_x1y1 = st.sidebar.columns([3, 3]) # Wider columns for sliders
x1 = col_x1y1[0].number_input("X1", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
y1 = col_x1y1[1].number_input("Y1", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# # Reduced spacing between sections
# st.sidebar.markdown("<br>", unsafe_allow_html=True)
col_x2y2 = st.sidebar.columns([3, 3]) # Wider columns for sliders
x2 = col_x2y2[0].number_input("X2", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
y2 = col_x2y2[1].number_input("Y2", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# # Reduced spacing between sections
# st.sidebar.markdown("<br>", unsafe_allow_html=True)
col_x3y3 = st.sidebar.columns([3, 3]) # Wider columns for sliders
x3 = col_x3y3[0].number_input("X3", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
y3 = col_x3y3[1].number_input("Y3", min_value=-100.0, max_value=100.0, step=0.1, format="%.3f")
# Add extra vertical spacing below the inputs
st.sidebar.markdown("<br>", unsafe_allow_html=True)
# Add "Solve Triangle" button centered in a new row
button_col = st.sidebar.columns([1, 2, 1]) # Center button using column proportions
if button_col[1].button("Solve Triangle"):
# Calculate the lengths of the sides of the triangle using Euclidean distance
a = calculate_distance(x2, y2, x3, y3)
b = calculate_distance(x1, y1, x3, y3)
c = calculate_distance(x1, y1, x2, y2)
# Validate if it's a valid triangle
if not is_valid_triangle(a, b, c):
st.error("The entered points do not form a valid triangle.")
return
# Calculate angles using the Law of Cosines
A = calculate_angle(a, b, c)
B = calculate_angle(b, a, c)
C = calculate_angle(c, a, b)
# Check if angles sum up to 180 degrees
if abs(A + B + C - 180) > 1e-2:
st.error("The sum of the angles is not 180 degrees.")
return
# Calculate area, perimeter, and radius of inscribed and circumscribed circles
area = calculate_area(a, b, c)
perimeter = calculate_perimeter(a, b, c)
radius_in = calculate_radius_inscribed_circle(a, b, c)
radius_circum = calculate_radius_circumscribed_circle(a, b, c)
# Calculate centroid, incenter, and circumcenter coordinates
G_x, G_y = calculate_centroid(x1, y1, x2, y2, x3, y3)
I_x, I_y = calculate_incenter(x1, y1, x2, y2, x3, y3, a, b, c)
U_x, U_y = calculate_circumcenter(x1, y1, x2, y2, x3, y3, a, b, c)
# Calculate midpoints of the sides
midpoints = calculate_midpoints(x1, y1, x2, y2, x3, y3)
# Display results in columns
col1, col2 = st.columns(2)
with col1:
st.subheader("Coordinates of Triangle:")
st.markdown(f"Vertex A: **({x1:.3f}, {y1:.3f})**")
st.markdown(f"Vertex B: **({x2:.3f}, {y2:.3f})**")
st.markdown(f"Vertex C: **({x3:.3f}, {y3:.3f})**")
with col2:
st.subheader("Mid-Points of Triangle:")
st.markdown(f"Midpoint of AB: **({midpoints[0][0]:.3f}, {midpoints[0][1]:.3f})**")
st.markdown(f"Midpoint of BC: **({midpoints[1][0]:.3f}, {midpoints[1][1]:.3f})**")
st.markdown(f"Midpoint of CA: **({midpoints[2][0]:.3f}, {midpoints[2][1]:.3f})**")
col1, col2 = st.columns(2)
with col1:
st.subheader("Angles of Triangle:")
st.markdown(f"Angle A: **{format_zero(A):.3f}°**")
st.markdown(f"Angle B: **{format_zero(B):.3f}°**")
st.markdown(f"Angle C: **{format_zero(C):.3f}°**")
with col2:
st.subheader("Sides of Triangle:")
st.markdown(f"Side a: **{format_zero(a):.3f}** units")
st.markdown(f"Side b: **{format_zero(b):.3f}** units")
st.markdown(f"Side c: **{format_zero(c):.3f}** units")
col1, col2 = st.columns(2)
with col1:
st.subheader("Incenter of Triangle:")
st.markdown(f"Coordinates: **({format_zero(I_x):.3f}, {format_zero(I_y):.3f})**")
st.markdown(f"Radius: **{radius_in:.3f}** units")
with col2:
st.subheader("Circumcenter of Triangle:")
st.markdown(f"Coordinates: **({format_zero(U_x):.3f}, {format_zero(U_y):.3f})**")
st.markdown(f"Radius: **{radius_circum:.3f}** units")
col1, col2, col3 = st.columns([1, 2, 1]) # Create three columns with relative widths
with col2: # Center column
st.subheader("Other Properties:")
st.markdown(f"Area: **{format_zero(area):.3f}** square units")
st.markdown(f"Perimeter: **{format_zero(perimeter):.3f}** units")
st.markdown(f"Centroid: **({format_zero(G_x):.3f}, {format_zero(G_y):.3f})**")
# Display triangle graph with midpoints and colored points
plot_triangle(x1, y1, x2, y2, x3, y3, I_x, I_y, U_x, U_y, G_x, G_y, midpoints, a, b, c)
if __name__ == "__main__":
main()
|