Trig_Angle_Calc / src /streamlit_app.py
NavyDevilDoc's picture
Update src/streamlit_app.py
9baa874 verified
import streamlit as st
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
from math import sin, cos, tan, asin, acos, atan2, sqrt, degrees, radians, pi
import time
def calculate_triangle_area(a, b, c):
"""Calculate triangle area using Heron's formula"""
s = (a + b + c) / 2 # semi-perimeter
area = sqrt(s * (s - a) * (s - b) * (s - c))
return area
def draw_triangle(side_a, side_b, side_c, angle_A, angle_B, angle_C, title="Triangle"):
"""Draw a triangle with labeled sides and angles using Plotly"""
# Place vertices (C at origin, B on x-axis)
C = np.array([0, 0])
B = np.array([side_a, 0])
A = np.array([side_b * cos(radians(angle_C)), side_b * sin(radians(angle_C))])
# Create triangle coordinates for plotting
triangle_x = [A[0], B[0], C[0], A[0]] # Close the triangle
triangle_y = [A[1], B[1], C[1], A[1]]
# Create the figure
fig = go.Figure()
# Add triangle fill
fig.add_trace(go.Scatter(
x=triangle_x,
y=triangle_y,
fill='toself',
fillcolor='rgba(173, 216, 230, 0.3)',
line=dict(color='blue', width=3),
mode='lines',
name='Triangle',
showlegend=False
))
# Add vertices
fig.add_trace(go.Scatter(
x=[A[0]], y=[A[1]],
mode='markers+text',
marker=dict(color='red', size=12),
text=['A'],
textposition='top center',
textfont=dict(size=16, color='black'),
name='Vertex A',
showlegend=True
))
fig.add_trace(go.Scatter(
x=[B[0]], y=[B[1]],
mode='markers+text',
marker=dict(color='green', size=12),
text=['B'],
textposition='bottom center',
textfont=dict(size=16, color='black'),
name='Vertex B',
showlegend=True
))
fig.add_trace(go.Scatter(
x=[C[0]], y=[C[1]],
mode='markers+text',
marker=dict(color='blue', size=12),
text=['C'],
textposition='middle left',
textfont=dict(size=16, color='black'),
name='Vertex C',
showlegend=True
))
# Calculate midpoints for side labels
mid_AB = (A + B) / 2
mid_BC = (B + C) / 2
mid_CA = (C + A) / 2
# Add side labels
fig.add_trace(go.Scatter(
x=[mid_AB[0]], y=[mid_AB[1]],
mode='text',
text=[f'c = {side_c:.2f}'],
textfont=dict(size=12, color='black'),
textposition='top center',
showlegend=False
))
fig.add_trace(go.Scatter(
x=[mid_BC[0]], y=[mid_BC[1]],
mode='text',
text=[f'a = {side_a:.2f}'],
textfont=dict(size=12, color='black'),
textposition='bottom center',
showlegend=False
))
fig.add_trace(go.Scatter(
x=[mid_CA[0]], y=[mid_CA[1]],
mode='text',
text=[f'b = {side_b:.2f}'],
textfont=dict(size=12, color='black'),
textposition='middle left',
showlegend=False
))
# Add angle labels
fig.add_trace(go.Scatter(
x=[A[0] - 0.3], y=[A[1] - 0.3],
mode='text',
text=[f'∠A = {angle_A:.1f}°'],
textfont=dict(size=10, color='black'),
showlegend=False
))
fig.add_trace(go.Scatter(
x=[B[0] + 0.2], y=[B[1] + 0.2],
mode='text',
text=[f'∠B = {angle_B:.1f}°'],
textfont=dict(size=10, color='black'),
showlegend=False
))
fig.add_trace(go.Scatter(
x=[C[0] + 0.2], y=[C[1] + 0.2],
mode='text',
text=[f'∠C = {angle_C:.1f}°'],
textfont=dict(size=10, color='black'),
showlegend=False
))
# Set layout
all_x = [A[0], B[0], C[0]]
all_y = [A[1], B[1], C[1]]
margin = 1.0
fig.update_layout(
title=dict(text=title, font=dict(size=18, color='black'), x=0.5),
xaxis=dict(
range=[min(all_x) - margin, max(all_x) + margin],
showgrid=True,
gridcolor='lightgray',
zeroline=True,
zerolinecolor='gray'
),
yaxis=dict(
range=[min(all_y) - margin, max(all_y) + margin],
showgrid=True,
gridcolor='lightgray',
zeroline=True,
zerolinecolor='gray',
scaleanchor="x",
scaleratio=1
),
plot_bgcolor='white',
paper_bgcolor='white',
width=700,
height=600,
margin=dict(l=50, r=50, t=80, b=50)
)
return fig
def draw_vectors(a_x, a_y, b_x, b_y, angle_between):
"""Draw two vectors and show the angle between them using Plotly"""
fig = go.Figure()
# Draw vectors from origin
fig.add_trace(go.Scatter(
x=[0, a_x], y=[0, a_y],
mode='lines+markers',
line=dict(color='red', width=4),
marker=dict(symbol='arrow', angle=90, size=15, color='red'),
name=f'Vector A ({a_x:.2f}, {a_y:.2f})'
))
fig.add_trace(go.Scatter(
x=[0, b_x], y=[0, b_y],
mode='lines+markers',
line=dict(color='blue', width=4),
marker=dict(symbol='arrow', angle=90, size=15, color='blue'),
name=f'Vector B ({b_x:.2f}, {b_y:.2f})'
))
# Create angle arc
magnitude_a = sqrt(a_x**2 + a_y**2)
magnitude_b = sqrt(b_x**2 + b_y**2)
angle_a = atan2(a_y, a_x)
angle_b = atan2(b_y, b_x)
if angle_a < angle_b:
arc_angles = np.linspace(angle_a, angle_b, 50)
else:
arc_angles = np.linspace(angle_b, angle_a, 50)
arc_radius = min(magnitude_a, magnitude_b) * 0.3
arc_x = arc_radius * np.cos(arc_angles)
arc_y = arc_radius * np.sin(arc_angles)
# Add angle arc
fig.add_trace(go.Scatter(
x=arc_x, y=arc_y,
mode='lines',
line=dict(color='green', width=4),
showlegend=False
))
# Add angle label
mid_angle = (angle_a + angle_b) / 2
label_x = (arc_radius + 0.5) * cos(mid_angle)
label_y = (arc_radius + 0.5) * sin(mid_angle)
fig.add_trace(go.Scatter(
x=[label_x], y=[label_y],
mode='text',
text=[f'{angle_between:.1f}°'],
textfont=dict(size=14, color='green'),
showlegend=False
))
# Add vector endpoint labels
fig.add_trace(go.Scatter(
x=[a_x], y=[a_y],
mode='text',
text=['A'],
textfont=dict(size=16, color='red'),
textposition='top right',
showlegend=False
))
fig.add_trace(go.Scatter(
x=[b_x], y=[b_y],
mode='text',
text=['B'],
textfont=dict(size=16, color='blue'),
textposition='top right',
showlegend=False
))
# Set layout
max_range = max(magnitude_a, magnitude_b) * 1.2
fig.update_layout(
title=dict(text=f'Vectors with {angle_between:.1f}° angle between them',
font=dict(size=18, color='black'), x=0.5),
xaxis=dict(
range=[-max_range * 0.1, max_range],
showgrid=True,
gridcolor='lightgray',
zeroline=True,
zerolinecolor='black',
zerolinewidth=2
),
yaxis=dict(
range=[-max_range * 0.1, max_range],
showgrid=True,
gridcolor='lightgray',
zeroline=True,
zerolinecolor='black',
zerolinewidth=2,
scaleanchor="x",
scaleratio=1
),
plot_bgcolor='white',
paper_bgcolor='white',
width=700,
height=600,
margin=dict(l=50, r=50, t=80, b=50)
)
return fig
def law_of_sines_calculator():
st.header("📏 Law of Sines Calculator")
st.markdown("**Formula:** a/sin(A) = b/sin(B) = c/sin(C)")
st.markdown("**Equivalent:** sin(A)/a = sin(B)/b = sin(C)/c")
# Add formula explanation
with st.expander("📚 Understanding the Law of Sines"):
st.markdown("""
The Law of Sines can be written in two equivalent forms:
**Form 1:** a/sin(A) = b/sin(B) = c/sin(C)
**Form 2:** sin(A)/a = sin(B)/b = sin(C)/c
Both forms are mathematically identical and lead to the same calculations:
- To find a side: side = (other_side × sin(opposite_angle)) / sin(known_angle)
- To find an angle: sin(angle) = (opposite_side × sin(known_angle)) / known_side
**Use the Law of Sines when you have:**
- **AAS (Angle-Angle-Side)**: Two angles and one side
- **ASA (Angle-Side-Angle)**: Two angles and the included side
- **SSA (Side-Side-Angle)**: Two sides and one angle (ambiguous case)
""")
# Add a visual demonstration of the relationship
with st.expander("🔍 See the calculation steps"):
st.markdown("""
**Example calculation process:**
If we know: angle A, angle B, and side a
**Step 1:** Find angle C
C = 180° - A - B
**Step 2:** Use Law of Sines to find side b
From: a/sin(A) = b/sin(B)
Rearrange: b = (a × sin(B)) / sin(A)
**Step 3:** Find side c
From: a/sin(A) = c/sin(C)
Rearrange: c = (a × sin(C)) / sin(A)
""")
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("📝 Input Triangle Data")
known_case = st.selectbox(
"What do you know about the triangle?",
["Two angles and one side (AAS/ASA)", "Two sides and one angle (SSA)"]
)
if known_case == "Two angles and one side (AAS/ASA)":
st.write("**Enter two angles and one side:**")
angle_A = st.number_input("Angle A (degrees):", min_value=0.1, max_value=179.9, value=60.0, key="sines_angleA")
angle_B = st.number_input("Angle B (degrees):", min_value=0.1, max_value=179.9, value=50.0, key="sines_angleB")
side_a = st.number_input("Side a (opposite to angle A):", min_value=0.1, value=10.0, key="sines_sidea")
# Calculate third angle
angle_C = 180 - angle_A - angle_B
if angle_C <= 0:
st.error("❌ Invalid triangle! Sum of angles must be less than 180°")
return
# Calculate other sides using Law of Sines
side_b = side_a * sin(radians(angle_B)) / sin(radians(angle_A))
side_c = side_a * sin(radians(angle_C)) / sin(radians(angle_A))
# Validate triangle
if side_b <= 0 or side_c <= 0:
st.error("❌ Invalid triangle! Check your inputs.")
return
else: # SSA case
st.write("**Enter two sides and one angle (ambiguous case):**")
side_a = st.number_input("Side a:", min_value=0.1, value=10.0, key="sines_ssa_sidea")
side_b = st.number_input("Side b:", min_value=0.1, value=8.0, key="sines_ssa_sideb")
angle_A = st.number_input("Angle A (opposite to side a):", min_value=0.1, max_value=179.9, value=60.0, key="sines_ssa_angleA")
# Check for validity
sin_B = side_b * sin(radians(angle_A)) / side_a
if sin_B > 1:
st.error("❌ No triangle possible with these measurements!")
return
elif abs(sin_B - 1) < 1e-10: # sin_B == 1 (within floating point precision)
angle_B = 90.0
angle_C = 90 - angle_A
side_c = side_a * cos(radians(angle_A))
st.info("✅ Right triangle solution found!")
else:
angle_B = degrees(asin(sin_B))
angle_C = 180 - angle_A - angle_B
side_c = side_a * sin(radians(angle_C)) / sin(radians(angle_A))
# Check for ambiguous case
if side_b < side_a and angle_A < 90:
angle_B2 = 180 - angle_B
angle_C2 = 180 - angle_A - angle_B2
if angle_C2 > 0:
side_c2 = side_a * sin(radians(angle_C2)) / sin(radians(angle_A))
st.warning(f"⚠️ Ambiguous case! Two triangles possible:")
st.write(f"**Triangle 1:** B = {angle_B:.2f}°, C = {angle_C:.2f}°, c = {side_c:.3f}")
st.write(f"**Triangle 2:** B = {angle_B2:.2f}°, C = {angle_C2:.2f}°, c = {side_c2:.3f}")
# Let user choose which triangle to display
triangle_choice = st.radio("Choose triangle to visualize:", ["Triangle 1", "Triangle 2"])
if triangle_choice == "Triangle 2":
angle_B, angle_C, side_c = angle_B2, angle_C2, side_c2
with col2:
st.subheader("📊 Results")
# Display results in a nice table
results_df = pd.DataFrame({
'Element': ['Side a', 'Side b', 'Side c', 'Angle A', 'Angle B', 'Angle C'],
'Value': [f'{side_a:.3f}', f'{side_b:.3f}', f'{side_c:.3f}',
f'{angle_A:.2f}°', f'{angle_B:.2f}°', f'{angle_C:.2f}°'],
'Type': ['Given' if known_case == "Two angles and one side (AAS/ASA)" else 'Given',
'Calculated' if known_case == "Two angles and one side (AAS/ASA)" else 'Given',
'Calculated',
'Given' if known_case == "Two angles and one side (AAS/ASA)" else 'Given',
'Given' if known_case == "Two angles and one side (AAS/ASA)" else 'Calculated',
'Calculated']
})
st.dataframe(results_df, use_container_width=True)
# Calculate area using formula: Area = (1/2)ab*sin(C)
area = 0.5 * side_a * side_b * sin(radians(angle_C))
perimeter = side_a + side_b + side_c
col_metric1, col_metric2 = st.columns(2)
with col_metric1:
st.metric("Area", f"{area:.3f} sq units")
with col_metric2:
st.metric("Perimeter", f"{perimeter:.3f} units")
# Draw the triangle
fig = draw_triangle(side_a, side_b, side_c, angle_A, angle_B, angle_C, "Law of Sines Triangle")
st.plotly_chart(fig, use_container_width=True)
def law_of_cosines_calculator():
st.header("📐 Law of Cosines Calculator")
st.markdown("**Formula:** c² = a² + b² - 2ab⋅cos(C)")
# Add formula explanation
with st.expander("📚 When to use Law of Cosines"):
st.markdown("""
Use the Law of Cosines when you have:
- **SSS (Side-Side-Side)**: All three sides known
- **SAS (Side-Angle-Side)**: Two sides and the included angle
This is especially useful when the Law of Sines doesn't apply directly.
""")
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("📝 Input Triangle Data")
known_case = st.selectbox(
"What do you know?",
["Three sides (SSS)", "Two sides and included angle (SAS)"]
)
if known_case == "Three sides (SSS)":
st.write("**Enter all three sides:**")
side_a = st.number_input("Side a:", min_value=0.1, value=5.0, key="cosines_sss_sidea")
side_b = st.number_input("Side b:", min_value=0.1, value=7.0, key="cosines_sss_sideb")
side_c = st.number_input("Side c:", min_value=0.1, value=9.0, key="cosines_sss_sidec")
# Check triangle inequality
if not (side_a + side_b > side_c and side_b + side_c > side_a and side_a + side_c > side_b):
st.error("❌ Invalid triangle! Triangle inequality not satisfied.")
st.write("**Triangle Inequality Rules:**")
st.write(f"• a + b > c: {side_a:.2f} + {side_b:.2f} = {side_a + side_b:.2f} {'✓' if side_a + side_b > side_c else '✗'} {side_c:.2f}")
st.write(f"• b + c > a: {side_b:.2f} + {side_c:.2f} = {side_b + side_c:.2f} {'✓' if side_b + side_c > side_a else '✗'} {side_a:.2f}")
st.write(f"• a + c > b: {side_a:.2f} + {side_c:.2f} = {side_a + side_c:.2f} {'✓' if side_a + side_c > side_b else '✗'} {side_b:.2f}")
return
# Calculate angles using Law of Cosines
try:
angle_A = degrees(acos((side_b**2 + side_c**2 - side_a**2) / (2 * side_b * side_c)))
angle_B = degrees(acos((side_a**2 + side_c**2 - side_b**2) / (2 * side_a * side_c)))
angle_C = 180 - angle_A - angle_B
except ValueError:
st.error("❌ Error calculating angles. Check your side lengths.")
return
else: # SAS case
st.write("**Enter two sides and the included angle:**")
side_a = st.number_input("Side a:", min_value=0.1, value=5.0, key="cosines_sas_sidea")
side_b = st.number_input("Side b:", min_value=0.1, value=7.0, key="cosines_sas_sideb")
angle_C = st.number_input("Angle C (between sides a and b):", min_value=0.1, max_value=179.9, value=60.0, key="cosines_sas_angleC")
# Calculate third side using Law of Cosines
side_c = sqrt(side_a**2 + side_b**2 - 2 * side_a * side_b * cos(radians(angle_C)))
# Calculate other angles using Law of Cosines
try:
angle_A = degrees(acos((side_b**2 + side_c**2 - side_a**2) / (2 * side_b * side_c)))
angle_B = 180 - angle_A - angle_C
except ValueError:
st.error("❌ Error calculating angles. Check your inputs.")
return
with col2:
st.subheader("📊 Results")
# Display results
results_df = pd.DataFrame({
'Element': ['Side a', 'Side b', 'Side c', 'Angle A', 'Angle B', 'Angle C'],
'Value': [f'{side_a:.3f}', f'{side_b:.3f}', f'{side_c:.3f}',
f'{angle_A:.2f}°', f'{angle_B:.2f}°', f'{angle_C:.2f}°'],
'Type': ['Given', 'Given',
'Given' if known_case == "Three sides (SSS)" else 'Calculated',
'Calculated', 'Calculated',
'Calculated' if known_case == "Three sides (SSS)" else 'Given']
})
st.dataframe(results_df, use_container_width=True)
# Calculate area and perimeter
area = calculate_triangle_area(side_a, side_b, side_c)
perimeter = side_a + side_b + side_c
col_metric1, col_metric2 = st.columns(2)
with col_metric1:
st.metric("Area", f"{area:.3f} sq units")
with col_metric2:
st.metric("Perimeter", f"{perimeter:.3f} units")
# Determine triangle type
if abs(angle_A - 90) < 0.01 or abs(angle_B - 90) < 0.01 or abs(angle_C - 90) < 0.01:
triangle_type = "Right Triangle"
elif angle_A > 90 or angle_B > 90 or angle_C > 90:
triangle_type = "Obtuse Triangle"
else:
triangle_type = "Acute Triangle"
st.info(f"**Triangle Type:** {triangle_type}")
# Draw the triangle
fig = draw_triangle(side_a, side_b, side_c, angle_A, angle_B, angle_C, "Law of Cosines Triangle")
st.plotly_chart(fig, use_container_width=True)
def vector_angle_calculator():
st.header("🔄 Vector Angle Calculator")
st.markdown("**Formula:** cos(θ) = (A⋅B) / (|A|⋅|B|)")
# Add explanation
with st.expander("📚 Understanding Vector Angles"):
st.markdown("""
**Dot Product Formula:** A⋅B = |A||B|cos(θ)
**Applications:**
- Physics: Work = Force⋅Displacement⋅cos(θ)
- Computer Graphics: Lighting calculations
- Engineering: Force analysis
- Navigation: Direction calculations
""")
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("📝 Enter Vectors")
# Vector input methods
input_method = st.radio("Input method:", ["Component form", "Magnitude & Direction"])
if input_method == "Component form":
st.write("**Vector A:**")
a_x = st.number_input("A_x component:", value=3.0, key="vector_ax")
a_y = st.number_input("A_y component:", value=4.0, key="vector_ay")
st.write("**Vector B:**")
b_x = st.number_input("B_x component:", value=1.0, key="vector_bx")
b_y = st.number_input("B_y component:", value=2.0, key="vector_by")
else:
st.write("**Vector A:**")
mag_a = st.number_input("Magnitude of A:", min_value=0.1, value=5.0, key="vector_mag_a")
dir_a = st.number_input("Direction of A (degrees):", value=53.0, key="vector_dir_a")
st.write("**Vector B:**")
mag_b = st.number_input("Magnitude of B:", min_value=0.1, value=2.24, key="vector_mag_b")
dir_b = st.number_input("Direction of B (degrees):", value=63.4, key="vector_dir_b")
# Convert to components
a_x = mag_a * cos(radians(dir_a))
a_y = mag_a * sin(radians(dir_a))
b_x = mag_b * cos(radians(dir_b))
b_y = mag_b * sin(radians(dir_b))
# Calculate vector properties
dot_product = a_x * b_x + a_y * b_y
magnitude_a = sqrt(a_x**2 + a_y**2)
magnitude_b = sqrt(b_x**2 + b_y**2)
if magnitude_a == 0 or magnitude_b == 0:
st.error("❌ Zero vector detected! Cannot calculate angle.")
return
cos_theta = dot_product / (magnitude_a * magnitude_b)
# Clamp to [-1, 1] to avoid floating point errors
cos_theta = max(-1, min(1, cos_theta))
angle_degrees = degrees(acos(cos_theta))
# Calculate cross product for 2D (gives scalar)
cross_product = a_x * b_y - a_y * b_x
with col2:
st.subheader("📊 Results")
# Vector information table
vector_info = pd.DataFrame({
'Property': ['A_x', 'A_y', 'B_x', 'B_y', '|A|', '|B|'],
'Value': [f'{a_x:.3f}', f'{a_y:.3f}', f'{b_x:.3f}', f'{b_y:.3f}',
f'{magnitude_a:.3f}', f'{magnitude_b:.3f}']
})
st.dataframe(vector_info, use_container_width=True)
# Key results
col_metric1, col_metric2 = st.columns(2)
with col_metric1:
st.metric("Dot Product (A⋅B)", f"{dot_product:.3f}")
st.metric("Angle", f"{angle_degrees:.2f}°")
with col_metric2:
st.metric("Cross Product (2D)", f"{cross_product:.3f}")
st.metric("cos(θ)", f"{cos_theta:.4f}")
# Vector relationship
if abs(dot_product) < 1e-10:
st.info("🔄 **Vectors are perpendicular (orthogonal)**")
elif cos_theta > 0:
st.info("📐 **Vectors point in similar directions (acute angle)**")
else:
st.info("📐 **Vectors point in opposite directions (obtuse angle)**")
# Draw vectors
fig = draw_vectors(a_x, a_y, b_x, b_y, angle_degrees)
st.plotly_chart(fig, use_container_width=True)
# Additional calculations
st.subheader("🧮 Additional Calculations")
# Unit vectors
unit_a_x = a_x / magnitude_a if magnitude_a != 0 else 0
unit_a_y = a_y / magnitude_a if magnitude_a != 0 else 0
unit_b_x = b_x / magnitude_b if magnitude_b != 0 else 0
unit_b_y = b_y / magnitude_b if magnitude_b != 0 else 0
st.write(f"**Unit vector A:** ({unit_a_x:.3f}, {unit_a_y:.3f})")
st.write(f"**Unit vector B:** ({unit_b_x:.3f}, {unit_b_y:.3f})")
# Vector sum and difference
sum_x, sum_y = a_x + b_x, a_y + b_y
diff_x, diff_y = a_x - b_x, a_y - b_y
st.write(f"**A + B:** ({sum_x:.3f}, {sum_y:.3f})")
st.write(f"**A - B:** ({diff_x:.3f}, {diff_y:.3f})")
def triangle_visualizer():
st.header("🎨 Interactive Triangle Visualizer")
st.markdown("Explore how changing triangle properties affects its shape and calculations!")
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("🎛️ Triangle Controls")
# Interactive sliders for triangle properties
side_a = st.slider("Side a:", min_value=1.0, max_value=15.0, value=8.0, step=0.1)
side_b = st.slider("Side b:", min_value=1.0, max_value=15.0, value=6.0, step=0.1)
angle_C = st.slider("Angle C (degrees):", min_value=10.0, max_value=170.0, value=60.0, step=1.0)
# Calculate using Law of Cosines
side_c = sqrt(side_a**2 + side_b**2 - 2 * side_a * side_b * cos(radians(angle_C)))
# Calculate other angles
try:
angle_A = degrees(acos((side_b**2 + side_c**2 - side_a**2) / (2 * side_b * side_c)))
angle_B = 180 - angle_A - angle_C
except ValueError:
st.error("Invalid triangle configuration!")
return
# Real-time calculations
area = 0.5 * side_a * side_b * sin(radians(angle_C))
perimeter = side_a + side_b + side_c
# Display live results
st.subheader("📊 Live Results")
col_live1, col_live2 = st.columns(2)
with col_live1:
st.metric("Side c", f"{side_c:.2f}")
st.metric("Angle A", f"{angle_A:.1f}°")
st.metric("Area", f"{area:.2f}")
with col_live2:
st.metric("Angle B", f"{angle_B:.1f}°")
st.metric("Perimeter", f"{perimeter:.2f}")
# Triangle type
if abs(angle_A - 90) < 0.1 or abs(angle_B - 90) < 0.1 or abs(angle_C - 90) < 0.1:
triangle_type = "Right"
elif angle_A > 90 or angle_B > 90 or angle_C > 90:
triangle_type = "Obtuse"
else:
triangle_type = "Acute"
st.info(f"**Triangle Type:** {triangle_type}")
with col2:
st.subheader("📐 Interactive Triangle")
# Draw the interactive triangle
fig = draw_triangle(side_a, side_b, side_c, angle_A, angle_B, angle_C, "Interactive Triangle")
st.plotly_chart(fig, use_container_width=True)
# Show which laws apply
st.subheader("📚 Applicable Laws")
st.write("**Given:** Two sides (a, b) and included angle (C)")
st.write("**Use:** Law of Cosines to find side c")
st.write("**Then:** Law of Cosines or Sines to find remaining angles")
# Show the calculations
with st.expander("🔍 See the calculations"):
st.write("**Step 1: Find side c using Law of Cosines**")
st.latex(r"c^2 = a^2 + b^2 - 2ab \cos(C)")
st.write(f"c² = {side_a}² + {side_b}² - 2({side_a})({side_b})cos({angle_C}°)")
st.write(f"c² = {side_a**2:.2f} + {side_b**2:.2f} - {2*side_a*side_b:.2f} × {cos(radians(angle_C)):.4f}")
st.write(f"c = {side_c:.3f}")
st.write("**Step 2: Find angle A using Law of Cosines**")
st.latex(r"\cos(A) = \frac{b^2 + c^2 - a^2}{2bc}")
st.write(f"cos(A) = ({side_b}² + {side_c:.2f}² - {side_a}²) / (2 × {side_b} × {side_c:.2f})")
st.write(f"A = {angle_A:.2f}°")
st.write("**Step 3: Find angle B**")
st.write(f"B = 180° - A - C = 180° - {angle_A:.2f}° - {angle_C}° = {angle_B:.2f}°")
def main():
st.set_page_config(page_title="Triangle Solver & Vector Calculator", page_icon="📐", layout="wide")
st.title("📐 Triangle Solver & Vector Calculator")
st.markdown("### Master the Law of Sines, Law of Cosines, and Vector Applications!")
# Add educational tips
tips = [
"💡 **Law of Sines**: Use when you have angle-side-angle (ASA) or side-angle-angle (SAA)",
"🎯 **Law of Cosines**: Use when you have side-side-side (SSS) or side-angle-side (SAS)",
"📊 **Vector Tip**: The angle between vectors uses the dot product formula",
"🔄 **Remember**: Always check if your triangle is valid (triangle inequality)",
"⚡ **Practical**: These laws help in navigation, engineering, and physics!"
]
st.info(np.random.choice(tips))
# Sidebar for mode selection
st.sidebar.header("🎛️ Calculator Mode")
mode = st.sidebar.radio(
"Choose what to calculate:",
["Law of Sines", "Law of Cosines", "Vector Angle Calculator", "Triangle Visualizer"]
)
# Educational content sidebar
with st.sidebar.expander("📚 Quick Reference"):
st.markdown("""
**Law of Sines:**
a/sin(A) = b/sin(B) = c/sin(C)
**Law of Cosines:**
c² = a² + b² - 2ab⋅cos(C)
**Vector Angle:**
cos(θ) = (A⋅B)/(|A||B|)
**Triangle Inequality:**
a + b > c, b + c > a, a + c > b
""")
# Main content based on mode
if mode == "Law of Sines":
law_of_sines_calculator()
elif mode == "Law of Cosines":
law_of_cosines_calculator()
elif mode == "Vector Angle Calculator":
vector_angle_calculator()
else:
triangle_visualizer()
# Footer with applications
st.markdown("---")
st.subheader("🌟 Real-World Applications")
app_col1, app_col2, app_col3 = st.columns(3)
with app_col1:
st.markdown("""
**🏗️ Engineering**
- Structural analysis
- Force calculations
- Bridge design
""")
with app_col2:
st.markdown("""
**🧭 Navigation**
- GPS systems
- Ship navigation
- Flight paths
""")
with app_col3:
st.markdown("""
**🎮 Technology**
- Computer graphics
- Game physics
- Robotics
""")
if __name__ == "__main__":
main()