Spaces:
Sleeping
Sleeping
| 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() |