Spaces:
Sleeping
Sleeping
| # import numpy as np | |
| # import streamlit as st | |
| # import plotly.express as px | |
| # import plotly.graph_objects as go | |
| # import pandas as pd | |
| # # Soccer field dimensions (in meters) | |
| # WIDTH = 80 # Width of the field | |
| # LENGTH = 120 # Length of the field | |
| # GOAL_HEIGHT = 2.44 # Standard goal height | |
| # PENALTY_AREA_WIDTH = 40.3 | |
| # PENALTY_AREA_DEPTH = 16.5 | |
| # GOAL_AREA_WIDTH = 18.32 | |
| # GOAL_AREA_DEPTH = 5.5 | |
| # GOAL_WIDTH = 7.32 # Standard width of a soccer goal | |
| # def create_field_df(): | |
| # """Create dataframes for different parts of the soccer field.""" | |
| # field_perimeter_bounds = [[0, 0, 0], [WIDTH, 0, 0], [WIDTH, LENGTH, 0], [0, LENGTH, 0], [0, 0, 0]] | |
| # field_df = pd.DataFrame(field_perimeter_bounds, columns=['x', 'y', 'z']) | |
| # field_df['line_group'] = 'field_perimeter' | |
| # field_df['color'] = 'field' | |
| # half_field_bounds = [[0, LENGTH / 2, 0], [WIDTH, LENGTH / 2, 0]] | |
| # half_df = pd.DataFrame(half_field_bounds, columns=['x', 'y', 'z']) | |
| # half_df['line_group'] = 'half_field' | |
| # half_df['color'] = 'field' | |
| # left_penalty_df = create_rectangle_df((WIDTH - PENALTY_AREA_WIDTH) / 2, 0, PENALTY_AREA_WIDTH, PENALTY_AREA_DEPTH, 'left_penalty_area') | |
| # right_penalty_df = create_rectangle_df((WIDTH - PENALTY_AREA_WIDTH) / 2, LENGTH - PENALTY_AREA_DEPTH, PENALTY_AREA_WIDTH, PENALTY_AREA_DEPTH, 'right_penalty_area') | |
| # left_goal_df = create_rectangle_df((WIDTH - GOAL_AREA_WIDTH) / 2, 0, GOAL_AREA_WIDTH, GOAL_AREA_DEPTH, 'left_goal_area') | |
| # right_goal_df = create_rectangle_df((WIDTH - GOAL_AREA_WIDTH) / 2, LENGTH - GOAL_AREA_DEPTH, GOAL_AREA_WIDTH, GOAL_AREA_DEPTH, 'right_goal_area') | |
| # return pd.concat([field_df, half_df, left_penalty_df, right_penalty_df, left_goal_df, right_goal_df]) | |
| # def create_rectangle_df(start_x, start_y, width, height, line_group): | |
| # """Create a dataframe representing a rectangle on the field.""" | |
| # rectangle_bounds = [ | |
| # [start_x, start_y, 0], | |
| # [start_x + width, start_y, 0], | |
| # [start_x + width, start_y + height, 0], | |
| # [start_x, start_y + height, 0], | |
| # [start_x, start_y, 0] | |
| # ] | |
| # df = pd.DataFrame(rectangle_bounds, columns=['x', 'y', 'z']) | |
| # df['line_group'] = line_group | |
| # df['color'] = 'field' | |
| # return df | |
| # def create_center_circle(): | |
| # """Create a 3D line trace for the center circle.""" | |
| # theta = np.linspace(0, 2 * np.pi, 100) | |
| # x = [(WIDTH / 2) + (9.15 * np.cos(t)) for t in theta] | |
| # y = [(LENGTH / 2) + (9.15 * np.sin(t)) for t in theta] | |
| # z = [0] * 100 | |
| # return go.Scatter3d(x=x, y=y, z=z, mode='lines', line=dict(color='white', width=2)) | |
| # def create_goalposts(): | |
| # """Create goalpost lines for both ends of the field.""" | |
| # goalposts = [] | |
| # goalposts.extend([ | |
| # go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) - (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| # go.Scatter3d(x=[(WIDTH / 2) + (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| # go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[GOAL_HEIGHT, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)) | |
| # ]) | |
| # goalposts.extend([ | |
| # go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) - (GOAL_WIDTH / 2)], y=[0, 0], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| # go.Scatter3d(x=[(WIDTH / 2) + (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[0, 0], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| # go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[0, 0], z=[GOAL_HEIGHT, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)) | |
| # ]) | |
| # return goalposts | |
| # def generate_trajectory(start_point, end_point, peak_height=10, num_coords=100, trajectory_type='parabolic'): | |
| # """Generate a trajectory (parabolic or linear) between start and end points.""" | |
| # shot_start_x, shot_start_y, start_z = start_point | |
| # hoop_x, hoop_y, end_z = end_point | |
| # if trajectory_type == 'parabolic': | |
| # distance_x = hoop_x - shot_start_x | |
| # a = -4 * peak_height / (distance_x ** 2) | |
| # shot_path_coords = [] | |
| # for index, x in enumerate(np.linspace(shot_start_x, hoop_x, num_coords + 1)): | |
| # z = a * (x - (shot_start_x + hoop_x) / 2) ** 2 + peak_height | |
| # y = shot_start_y + (hoop_y - shot_start_y) * (index / num_coords) | |
| # shot_path_coords.append([x, y, z]) | |
| # shot_path_coords[0][2] = start_z # Ensure start z is as specified | |
| # shot_path_coords[-1][2] = end_z # Ensure end z is as specified | |
| # elif trajectory_type == 'linear': | |
| # shot_path_coords = [] | |
| # for index, x in enumerate(np.linspace(shot_start_x, hoop_x, num_coords + 1)): | |
| # y = shot_start_y + (hoop_y - shot_start_y) * (index / num_coords) | |
| # z = start_z + (end_z - start_z) * (index / num_coords) | |
| # shot_path_coords.append([x, y, z]) | |
| # return pd.DataFrame(shot_path_coords, columns=['x', 'y', 'z']) | |
| # def plot_trajectories(fig, start_points, end_points, trajectory_type='parabolic', peak_height=10, num_coords=100): | |
| # """Plot multiple trajectories on the field.""" | |
| # for start_point, end_point in zip(start_points, end_points): | |
| # trajectory_df = generate_trajectory(start_point, end_point, peak_height, num_coords, trajectory_type) | |
| # fig.add_trace(go.Scatter3d( | |
| # y=trajectory_df['x'], | |
| # x=trajectory_df['y'], | |
| # z=trajectory_df['z'], | |
| # mode='lines', | |
| # line=dict(color='red', width=4) | |
| # )) | |
| # fig.add_trace(go.Scatter3d( | |
| # y=[trajectory_df['x'].iloc[0], trajectory_df['x'].iloc[-1]], | |
| # x=[trajectory_df['y'].iloc[0], trajectory_df['y'].iloc[-1]], | |
| # z=[trajectory_df['z'].iloc[0], trajectory_df['z'].iloc[-1]], | |
| # mode='markers', | |
| # marker=dict(size=3, color='red') | |
| # )) | |
| # def create_soccer_field_plot(): | |
| # """Create a 3D soccer field plot with trajectories.""" | |
| # field_df = create_field_df() | |
| # fig = px.line_3d( | |
| # data_frame=field_df, x='x', y='y', z='z', line_group='line_group', color='color', | |
| # color_discrete_map={'field': '#FFFFFF'} | |
| # ) | |
| # fig.add_trace(go.Mesh3d( | |
| # x=[0, WIDTH, WIDTH, 0], | |
| # y=[0, 0, LENGTH, LENGTH], | |
| # z=[0, 0, 0, 0], | |
| # color='rgb(0, 128, 0)', | |
| # opacity=0.5 | |
| # )) | |
| # fig.add_trace(create_center_circle()) | |
| # for goalpost in create_goalposts(): | |
| # fig.add_trace(goalpost) | |
| # max_dimension = max(WIDTH, LENGTH, GOAL_HEIGHT) | |
| # fig.update_layout( | |
| # scene=dict( | |
| # aspectmode="manual", | |
| # aspectratio=dict(x=1, y=1, z=0.125), | |
| # xaxis=dict( | |
| # range=[-10, max_dimension + 10], | |
| # visible=False | |
| # ), | |
| # yaxis=dict( | |
| # range=[-10, max_dimension + 10], | |
| # visible=False | |
| # ), | |
| # zaxis=dict( | |
| # range=[0, 15], | |
| # visible=False | |
| # ), | |
| # camera=dict( | |
| # eye=dict(x=0.34, y=0, z=0.45) | |
| # ), | |
| # ), | |
| # paper_bgcolor='rgba(0,0,0,0)', | |
| # plot_bgcolor='rgba(0,0,0,0)', | |
| # showlegend=False, | |
| # ) | |
| # return fig | |
| # def main_3D_pitch(start_points, end_points, trajectory_type='linear'): | |
| # st.title("3D Soccer Field Trajectory Visualization") | |
| # fig = create_soccer_field_plot() | |
| # plot_trajectories(fig, start_points, end_points, trajectory_type=trajectory_type, peak_height=5, num_coords=100) | |
| # st.plotly_chart(fig) | |
| import numpy as np | |
| import streamlit as st | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| import pandas as pd | |
| # Soccer field dimensions (in meters) | |
| WIDTH = 80 # Width of the field | |
| LENGTH = 120 # Length of the field | |
| GOAL_HEIGHT = 2.44 # Standard goal height | |
| PENALTY_AREA_WIDTH = 40.3 | |
| PENALTY_AREA_DEPTH = 16.5 | |
| GOAL_AREA_WIDTH = 18.32 | |
| GOAL_AREA_DEPTH = 5.5 | |
| GOAL_WIDTH = 7.32 # Standard width of a soccer goal | |
| def create_field_df(): | |
| """Create dataframes for different parts of the soccer field.""" | |
| field_perimeter_bounds = [[0, 0, 0], [WIDTH, 0, 0], [WIDTH, LENGTH, 0], [0, LENGTH, 0], [0, 0, 0]] | |
| field_df = pd.DataFrame(field_perimeter_bounds, columns=['x', 'y', 'z']) | |
| field_df['line_group'] = 'field_perimeter' | |
| field_df['color'] = 'field' | |
| half_field_bounds = [[0, LENGTH / 2, 0], [WIDTH, LENGTH / 2, 0]] | |
| half_df = pd.DataFrame(half_field_bounds, columns=['x', 'y', 'z']) | |
| half_df['line_group'] = 'half_field' | |
| half_df['color'] = 'field' | |
| left_penalty_df = create_rectangle_df((WIDTH - PENALTY_AREA_WIDTH) / 2, 0, PENALTY_AREA_WIDTH, PENALTY_AREA_DEPTH, 'left_penalty_area') | |
| right_penalty_df = create_rectangle_df((WIDTH - PENALTY_AREA_WIDTH) / 2, LENGTH - PENALTY_AREA_DEPTH, PENALTY_AREA_WIDTH, PENALTY_AREA_DEPTH, 'right_penalty_area') | |
| left_goal_df = create_rectangle_df((WIDTH - GOAL_AREA_WIDTH) / 2, 0, GOAL_AREA_WIDTH, GOAL_AREA_DEPTH, 'left_goal_area') | |
| right_goal_df = create_rectangle_df((WIDTH - GOAL_AREA_WIDTH) / 2, LENGTH - GOAL_AREA_DEPTH, GOAL_AREA_WIDTH, GOAL_AREA_DEPTH, 'right_goal_area') | |
| return pd.concat([field_df, half_df, left_penalty_df, right_penalty_df, left_goal_df, right_goal_df]) | |
| def create_rectangle_df(start_x, start_y, width, height, line_group): | |
| """Create a dataframe representing a rectangle on the field.""" | |
| rectangle_bounds = [ | |
| [start_x, start_y, 0], | |
| [start_x + width, start_y, 0], | |
| [start_x + width, start_y + height, 0], | |
| [start_x, start_y + height, 0], | |
| [start_x, start_y, 0] | |
| ] | |
| df = pd.DataFrame(rectangle_bounds, columns=['x', 'y', 'z']) | |
| df['line_group'] = line_group | |
| df['color'] = 'field' | |
| return df | |
| def create_center_circle(): | |
| """Create a 3D line trace for the center circle.""" | |
| theta = np.linspace(0, 2 * np.pi, 100) | |
| x = [(WIDTH / 2) + (9.15 * np.cos(t)) for t in theta] | |
| y = [(LENGTH / 2) + (9.15 * np.sin(t)) for t in theta] | |
| z = [0] * 100 | |
| return go.Scatter3d(x=x, y=y, z=z, mode='lines', line=dict(color='white', width=2)) | |
| def create_goalposts(): | |
| """Create goalpost lines for both ends of the field.""" | |
| goalposts = [] | |
| goalposts.extend([ | |
| go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) - (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| go.Scatter3d(x=[(WIDTH / 2) + (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[LENGTH, LENGTH], z=[GOAL_HEIGHT, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)) | |
| ]) | |
| goalposts.extend([ | |
| go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) - (GOAL_WIDTH / 2)], y=[0, 0], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| go.Scatter3d(x=[(WIDTH / 2) + (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[0, 0], z=[0, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)), | |
| go.Scatter3d(x=[(WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2)], y=[0, 0], z=[GOAL_HEIGHT, GOAL_HEIGHT], mode='lines', line=dict(color='black', width=4)) | |
| ]) | |
| return goalposts | |
| def create_goal_net(start_x, end_x, start_y, end_y, height, width): | |
| """Create a 3D mesh for the goal net.""" | |
| x = [start_x, end_x, end_x, start_x, start_x] | |
| y = [start_y, start_y, end_y, end_y, start_y] | |
| z = [height, height, height, height, height] | |
| return go.Mesh3d(x=x, y=y, z=z, opacity=0.1, color='blue') | |
| def generate_trajectory(start_point, end_point, peak_height=10, num_coords=100, trajectory_type='parabolic'): | |
| """Generate a trajectory (parabolic or linear) between start and end points.""" | |
| shot_start_x, shot_start_y, start_z = start_point | |
| hoop_x, hoop_y, end_z = end_point | |
| if trajectory_type == 'parabolic': | |
| distance_x = hoop_x - shot_start_x | |
| a = -4 * peak_height / (distance_x ** 2) | |
| shot_path_coords = [] | |
| for index, x in enumerate(np.linspace(shot_start_x, hoop_x, num_coords + 1)): | |
| z = a * (x - (shot_start_x + hoop_x) / 2) ** 2 + peak_height | |
| y = shot_start_y + (hoop_y - shot_start_y) * (index / num_coords) | |
| shot_path_coords.append([x, y, z]) | |
| shot_path_coords[0][2] = start_z # Ensure start z is as specified | |
| shot_path_coords[-1][2] = end_z # Ensure end z is as specified | |
| elif trajectory_type == 'linear': | |
| shot_path_coords = [] | |
| for index, x in enumerate(np.linspace(shot_start_x, hoop_x, num_coords + 1)): | |
| y = shot_start_y + (hoop_y - shot_start_y) * (index / num_coords) | |
| z = start_z + (end_z - start_z) * (index / num_coords) | |
| shot_path_coords.append([x, y, z]) | |
| return pd.DataFrame(shot_path_coords, columns=['x', 'y', 'z']) | |
| def plot_trajectories(fig, start_points, end_points, trajectory_type='parabolic', peak_height=10, num_coords=100): | |
| """Plot multiple trajectories on the field.""" | |
| for start_point, end_point in zip(start_points, end_points): | |
| trajectory_df = generate_trajectory(start_point, end_point, peak_height, num_coords, trajectory_type) | |
| fig.add_trace(go.Scatter3d( | |
| y=trajectory_df['x'], | |
| x=trajectory_df['y'], | |
| z=trajectory_df['z'], | |
| mode='lines', | |
| line=dict(color='red', width=4) | |
| )) | |
| fig.add_trace(go.Scatter3d( | |
| y=[trajectory_df['x'].iloc[0], trajectory_df['x'].iloc[-1]], | |
| x=[trajectory_df['y'].iloc[0], trajectory_df['y'].iloc[-1]], | |
| z=[trajectory_df['z'].iloc[0], trajectory_df['z'].iloc[-1]], | |
| mode='markers', | |
| marker=dict(size=3, color='red') | |
| )) | |
| def create_soccer_field_plot(): | |
| """Create a 3D soccer field plot with trajectories.""" | |
| field_df = create_field_df() | |
| fig = px.line_3d( | |
| data_frame=field_df, x='x', y='y', z='z', line_group='line_group', color='color', | |
| color_discrete_map={'field': '#FFFFFF'} | |
| ) | |
| fig.add_trace(go.Mesh3d( | |
| x=[0, WIDTH, WIDTH, 0], | |
| y=[0, 0, LENGTH, LENGTH], | |
| z=[0, 0, 0, 0], | |
| color='rgb(0, 128, 0)', | |
| opacity=0.5 | |
| )) | |
| fig.add_trace(create_center_circle()) | |
| for goalpost in create_goalposts(): | |
| fig.add_trace(goalpost) | |
| # # Add goal nets | |
| # fig.add_trace(create_goal_net((WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2), 0, -GOAL_HEIGHT, GOAL_HEIGHT, GOAL_WIDTH)) | |
| # fig.add_trace(create_goal_net((WIDTH / 2) - (GOAL_WIDTH / 2), (WIDTH / 2) + (GOAL_WIDTH / 2), LENGTH, LENGTH + GOAL_HEIGHT, GOAL_HEIGHT, GOAL_WIDTH)) | |
| max_dimension = max(WIDTH, LENGTH, GOAL_HEIGHT) | |
| fig.update_layout( | |
| scene=dict( | |
| aspectmode="manual", | |
| aspectratio=dict(x=1, y=1, z=0.125), | |
| xaxis=dict( | |
| range=[-10, max_dimension + 10], | |
| visible=False | |
| ), | |
| yaxis=dict( | |
| range=[-10, max_dimension + 10], | |
| visible=False | |
| ), | |
| zaxis=dict( | |
| range=[0, 15], | |
| visible=False | |
| ), | |
| camera=dict( | |
| eye=dict(x=0.34, y=0, z=0.45) | |
| ), | |
| ), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| showlegend=False, | |
| ) | |
| return fig | |
| def main_3D_pitch(start_points, end_points, trajectory_type='linear'): | |
| st.title("3D Soccer Field Trajectory Visualization") | |
| fig = create_soccer_field_plot() | |
| plot_trajectories(fig, start_points, end_points, trajectory_type=trajectory_type, peak_height=5, num_coords=100) | |
| st.plotly_chart(fig) | |