diff --git a/files/inifile.json b/files/inifile.json index 9325d4b..1c9747c 100644 --- a/files/inifile.json +++ b/files/inifile.json @@ -20,7 +20,7 @@ "simulation_parameters": { "fps": 100, "time_step": 0.001, - "number_agents": 82, + "number_agents": 20, "simulation_time": 200 }, "measurement_line": { @@ -87,71 +87,29 @@ } ] }, - "accessible_areas": [ + "accessible_areas": [ { "id": 1, "vertices": [ [ - 47.0, - 100.0 + -3.5, + -1.0 ], [ - 60.0, - 100.0 + 3.5, + -1.0 ], [ - 60.0, - 104.0 + 3.5, + 19.0 ], [ - 47.0, - 104.0 - ] - ] - }, - { - "id": 2, - "vertices": [ - [ - 60.0, - 101.7 - ], - [ - 62.0, - 101.7 - ], - [ - 62.0, - 102.3 - ], - [ - 60.0, - 102.3 - ] - ] - }, - { - "id": 3, - "vertices": [ - [ - 62.0, - 100.0 - ], - [ - 65.0, - 100.0 - ], - [ - 65.0, - 104.0 - ], - [ - 62.0, - 104.0 + -3.5, + 19.0 ] ] } - ], + ], "destinations": [ { "id": 1, @@ -225,24 +183,24 @@ "distribution_polygons": [ { "id": 1, - "vertices": [ + "vertices": [ [ - 48.0, - 100.0 + -3.5, + -1.0 ], [ - 55.0, - 100.0 + 3.5, + -1.0 ], [ - 55.0, - 104.0 + 3.5, + 19.0 ], [ - 48.0, - 104.0 + -3.5, + 19.0 ] - ] + ] } - ] + ] } diff --git a/positions.ipynb b/positions.ipynb index d81e7fc..91e7c71 100644 --- a/positions.ipynb +++ b/positions.ipynb @@ -320,53 +320,53 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "# # Parse the WKT polygon\n", - "# geometry2 = from_wkt(\n", - "# \"POLYGON ((-8.88 -7.63, 8.3 -7.63, 8.3 27.95, -8.88 27.95, -8.88 -7.63), (-3.54 -1.13, -3.57 19.57, -1.52 19.57, -1.37 19.71, -0.87 19.71, -0.72 19.57, -0.42 19.57, -0.27 19.71, -0.27 21.09, -0.42 21.23, -0.72 21.23, -0.87 21.09, -1.37 21.09, -1.52 21.23, -1.67 21.23, -1.67 21.18, -1.545 21.18, -1.4200000000000002 21.065, -1.4200000000000002 19.735, -1.545 19.62, -3.6199999999999997 19.62, -3.59 -1.13, -3.54 -1.13), (3.57 -0.89, 3.64 19.64, 1.47 19.57, 1.32 19.71, 0.82 19.71, 0.67 19.57, 0.38 19.57, 0.23 19.71, 0.23 21.09, 0.38 21.23, 0.67 21.23, 0.82 21.09, 1.32 21.09, 1.47 21.23, 1.62 21.23, 1.62 21.18, 1.4949999999999999 21.18, 1.37 21.065, 1.37 19.735, 1.4949999999999999 19.62, 3.69 19.69, 3.6199999999999997 -0.89, 3.57 -0.89))\"\n", - "# )\n", + "# Parse the WKT polygon\n", + "geometry2 = from_wkt(\n", + " \"POLYGON ((-8.88 -7.63, 8.3 -7.63, 8.3 27.95, -8.88 27.95, -8.88 -7.63), (-3.54 -1.13, -3.57 19.57, -1.52 19.57, -1.37 19.71, -0.87 19.71, -0.72 19.57, -0.42 19.57, -0.27 19.71, -0.27 21.09, -0.42 21.23, -0.72 21.23, -0.87 21.09, -1.37 21.09, -1.52 21.23, -1.67 21.23, -1.67 21.18, -1.545 21.18, -1.4200000000000002 21.065, -1.4200000000000002 19.735, -1.545 19.62, -3.6199999999999997 19.62, -3.59 -1.13, -3.54 -1.13), (3.57 -0.89, 3.64 19.64, 1.47 19.57, 1.32 19.71, 0.82 19.71, 0.67 19.57, 0.38 19.57, 0.23 19.71, 0.23 21.09, 0.38 21.23, 0.67 21.23, 0.82 21.09, 1.32 21.09, 1.47 21.23, 1.62 21.23, 1.62 21.18, 1.4949999999999999 21.18, 1.37 21.065, 1.37 19.735, 1.4949999999999999 19.62, 3.69 19.69, 3.6199999999999997 -0.89, 3.57 -0.89))\"\n", + ")\n", "\n", "\n", - "# # Extract exterior coordinates\n", - "# exterior_x, exterior_y = geometry2.exterior.xy\n", + "# Extract exterior coordinates\n", + "exterior_x, exterior_y = geometry2.exterior.xy\n", "\n", - "# # Extract interior coordinates (holes)\n", - "# interiors = [list(interior.coords.xy) for interior in geometry2.interiors]\n", - "# exterior_x = list(geometry2.exterior.xy[0])\n", - "# exterior_y = list(geometry2.exterior.xy[1])\n", + "# Extract interior coordinates (holes)\n", + "interiors = [list(interior.coords.xy) for interior in geometry2.interiors]\n", + "exterior_x = list(geometry2.exterior.xy[0])\n", + "exterior_y = list(geometry2.exterior.xy[1])\n", "\n", - "# # Extract interior coordinates (holes) as lists\n", - "# interiors = [\n", - "# (list(interior.xy[0]), list(interior.xy[1])) for interior in geometry2.interiors\n", - "# ]\n", + "# Extract interior coordinates (holes) as lists\n", + "interiors = [\n", + " (list(interior.xy[0]), list(interior.xy[1])) for interior in geometry2.interiors\n", + "]\n", "\n", - "# # Create the figure\n", - "# fig = go.Figure()\n", + "# Create the figure\n", + "fig = go.Figure()\n", "\n", - "# # Plot exterior\n", - "# fig.add_trace(go.Scatter(x=exterior_x, y=exterior_y, mode=\"lines\", name=\"Exterior\"))\n", + "# Plot exterior\n", + "fig.add_trace(go.Scatter(x=exterior_x, y=exterior_y, mode=\"lines\", name=\"Exterior\"))\n", "\n", - "# # Plot interiors (holes)\n", - "# for i, (x, y) in enumerate(interiors):\n", - "# fig.add_trace(go.Scatter(x=x, y=y, mode=\"lines+markers\", name=f\"Interior {i+1}\"))\n", - "# print(f\"Interior {i+1}. {x = }, {y = }\")\n", + "# Plot interiors (holes)\n", + "for i, (x, y) in enumerate(interiors):\n", + " fig.add_trace(go.Scatter(x=x, y=y, mode=\"lines+markers\", name=f\"Interior {i+1}\"))\n", + " print(f\"Interior {i+1}. {x = }, {y = }\")\n", "\n", "\n", "\n", - "# # fig.add_trace(go.Scatter(x=combined_x, y=combined_y, mode='lines+markers', fill='toself', name='Combined Polygon'))\n", + "# fig.add_trace(go.Scatter(x=combined_x, y=combined_y, mode='lines+markers', fill='toself', name='Combined Polygon'))\n", "\n", - "# # Update layout\n", - "# fig.update_layout(\n", - "# title=\"Polygon with Interior Holes\",\n", - "# xaxis_title=\"X Coordinate\",\n", - "# yaxis_title=\"Y Coordinate\",\n", - "# showlegend=True,\n", - "# width=600,\n", - "# height=600,\n", - "# )\n" + "# Update layout\n", + "fig.update_layout(\n", + " title=\"Polygon with Interior Holes\",\n", + " xaxis_title=\"X Coordinate\",\n", + " yaxis_title=\"Y Coordinate\",\n", + " showlegend=True,\n", + " width=600,\n", + " height=600,\n", + ")\n" ] }, { @@ -438,13 +438,13 @@ "outputs": [], "source": [ "walkable_area = pedpy.WalkableArea(geometry)\n", - "for filename in filenames:\n", + "for filename in filenames[0:1]:\n", " df, frame_after_decrease = get_first_frame_pedestrian_passes_line(filename)\n", " df['ox'] = 0.0\n", " df['oy'] = 0.1\n", " delta_frame = 20\n", " start = frame_after_decrease - delta_frame\n", - " end = frame_after_decrease + 3*delta_frame\n", + " end = frame_after_decrease + 100*delta_frame\n", " df = df[(df['frame'] >= start) & (df['frame'] <= end)]\n", " trajectory_data = pedpy.TrajectoryData(df, frame_rate=50)\n", " anim = animate(trajectory_data, walkable_area, every_nth_frame=1, title_note=f'{extract_title(filename)}, start={frame_after_decrease}')\n", @@ -466,41 +466,38 @@ "metadata": {}, "outputs": [], "source": [ - "# filename = filenames[0]\n", - "# df = pd.read_csv(\n", - "# filename, sep=\"\\t\", names=[\"id\", \"frame\", \"x\", \"y\", \"z\", \"m\"], comment=\"#\"\n", - "# )\n", + "filename = filenames[0]\n", + "df = pd.read_csv(\n", + " filename, sep=\"\\t\", names=[\"id\", \"frame\", \"x\", \"y\", \"z\", \"m\"], comment=\"#\"\n", + " )\n", "\n", "\n", - "# threshold = 0.1\n", - "# dy= 1\n", - "# ped = 70\n", - "# df_ped = df[(df['frame']>=frame_after_decrease) & (df['id']==ped)]\n", - "# def premovement_frame(df_ped, threshold, dy):\n", - "# premovement_frame = pd.NA\n", - "# while pd.isna(premovement_frame):\n", - "# premovement_frame = df_ped[df_ped['y'].diff(dy).abs() > threshold]['frame'].min()\n", - "# dy += 1\n", - "# return premovement_frame, dy\n", + "threshold = 0.1\n", + "dy= 1\n", + "ped = 70\n", + "df_ped = df[(df['frame']>=frame_after_decrease) & (df['id']==ped)]\n", + "def premovement_frame(df_ped, threshold, dy):\n", + " premovement_frame = pd.NA\n", + " while pd.isna(premovement_frame):\n", + " premovement_frame = df_ped[df_ped['y'].diff(dy).abs() > threshold]['frame'].min()\n", + " dy += 1\n", + " return premovement_frame, dy\n", "\n", "\n", "\n", - "# premovement_frame, dy = premovement_frame(df_ped, threshold, dy)\n", + "premovement_frame, dy = premovement_frame(df_ped, threshold, dy)\n", "\n", - "# print(f\"{premovement_frame = }, {dy = }\")\n", - "# plt.plot( df_ped['frame'], df_ped['y'],'-k', ms=1, alpha=0.6)\n", - "# plt.plot(premovement_frame, df_ped[df_ped['frame']==premovement_frame]['y'], 'ro', label='Pre-movement frame')\n", - "# plt.ylabel('Y Position')\n", - "# plt.xlabel('Frame')\n", - "# plt.title(f'Pedestrian {ped}. {premovement_frame = }, {dy = }')\n" + "print(f\"{premovement_frame = }, {dy = }\")\n", + "plt.plot( df_ped['frame'], df_ped['y'],'-k', ms=1, alpha=0.6)\n", + "plt.plot(premovement_frame, df_ped[df_ped['frame']==premovement_frame]['y'], 'ro', label='Pre-movement frame')\n", + "y_pos = df_ped[df_ped['frame'] == premovement_frame]['y'].values[0]\n", + "print(y_pos)\n", + "plt.text(premovement_frame, y_pos, f'({premovement_frame}, {y_pos:.2f})', \n", + " verticalalignment='bottom', horizontalalignment='right')\n", + "plt.ylabel('Y Position')\n", + "plt.xlabel('Frame')\n", + "plt.title(f'Pedestrian {ped}. {premovement_frame = }, {dy = }')\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/simulation.py b/simulation.py index 2cf76c9..ce4805b 100644 --- a/simulation.py +++ b/simulation.py @@ -151,15 +151,14 @@ def init_simulation( :returns: """ accessible_areas = parse_accessible_areas(_data) + if from_file: + logging.info(f"Init geometry from WKT") geometry = from_wkt( "POLYGON ((-8.88 -7.63, 8.3 -7.63, 8.3 27.95, -8.88 27.95, -8.88 -7.63), (-3.54 -1.13, -3.57 19.57, -1.52 19.57, -1.37 19.71, -0.87 19.71, -0.72 19.57, -0.42 19.57, -0.27 19.71, -0.27 21.09, -0.42 21.23, -0.72 21.23, -0.87 21.09, -1.37 21.09, -1.52 21.23, -1.67 21.23, -1.67 21.18, -1.545 21.18, -1.4200000000000002 21.065, -1.4200000000000002 19.735, -1.545 19.62, -3.6199999999999997 19.62, -3.59 -1.13, -3.54 -1.13), (3.57 -0.89, 3.64 19.64, 1.47 19.57, 1.32 19.71, 0.82 19.71, 0.67 19.57, 0.38 19.57, 0.23 19.71, 0.23 21.09, 0.38 21.23, 0.67 21.23, 0.82 21.09, 1.32 21.09, 1.47 21.23, 1.62 21.23, 1.62 21.18, 1.4949999999999999 21.18, 1.37 21.065, 1.37 19.735, 1.4949999999999999 19.62, 3.69 19.69, 3.6199999999999997 -0.89, 3.57 -0.89))" ) - # geometry with two doors - # geometry = from_wkt( - # "POLYGON ((-8.88 -7.63, 8.3 -7.63, 8.3 27.95, -8.88 27.95, -8.88 -7.63), (-3.54 -1.13, -3.57 19.57, -1.52 19.57, -1.37 19.71, -1.37 21.09, -1.52 21.23, -1.67 21.23, -1.67 21.18, -1.545 21.18, -1.4200000000000002 21.065, -1.4200000000000002 19.735, -1.545 19.62, -3.6199999999999997 19.62, -3.59 -1.13, -3.54 -1.13), (3.57 -0.89, 3.64 19.64, 1.47 19.57, 1.32 19.71, 1.32 21.09, 1.47 21.23, 1.62 21.23, 1.62 21.18, 1.4949999999999999 21.18, 1.37 21.065, 1.37 19.735, 1.4949999999999999 19.62, 3.69 19.69, 3.6199999999999997 -0.89, 3.57 -0.89), (0.67 19.57, 0.82 19.71, 0.82 21.09, 0.67 21.23, 0.38 21.23, 0.23 21.09, 0.23 19.71, 0.38 19.57, 0.67 19.57), (-0.42 19.57, -0.27 19.71, -0.27 21.09, -0.42 21.23, -0.72 21.23, -0.87 21.09, -0.87 19.71, -0.72 19.57, -0.42 19.57))" - # ) else: + logging.info("Init geometry from data") geometry = build_geometry(accessible_areas) # areas = build_areas(destinations, labels) simulation = jps.Simulation( @@ -352,23 +351,6 @@ def init_positions(_data: Dict[str, Any], _number_agents: int) -> List[Point]: positions = [] seed = int(_data["motivation_parameters"]["seed"]) total_agents = _number_agents - for s_polygon in distribution_polygons.values(): - logging.info(f"Distribute {total_agents} agents") - pos = distribute_by_number( - polygon=s_polygon, - number_of_agents=total_agents, - distance_to_agents=0.4, - distance_to_polygon=0.2, - seed=seed, - ) - total_agents -= _number_agents - positions += pos - if not total_agents: - break - distribution_polygons = parse_distribution_polygons(_data) - positions = [] - seed = int(_data["motivation_parameters"]["seed"]) - total_agents = _number_agents for s_polygon in distribution_polygons.values(): logging.info(f"Distribute {total_agents} agents") pos = distribute_by_number( @@ -407,8 +389,27 @@ def read_positions_from_csv(file_path: str = "points.csv") -> List[Point]: return points +def get_agent_positions(_data: Dict[str, Any]) -> Tuple[List[Point], int]: + """Get agent positions either from a file or generate them.""" + if "init_positions_file" in _data: + positions_file = _data["init_positions_file"] + if pathlib.Path(positions_file).exists(): + logging.info(f"Reading positions from file: {positions_file}") + positions = read_positions_from_csv(file_path=positions_file) + num_agents = len(positions) + _data["simulation_parameters"]["number_agents"] = num_agents + logging.info(f"Number of agents from file: {num_agents}") + else: + raise FileNotFoundError(f"Positions file {positions_file} does not exist!") + else: + num_agents = parse_number_agents(_data) + logging.info(f"Generating {num_agents} agent positions") + positions = init_positions(_data, num_agents) + + return positions, num_agents + + def init_and_run_simulation( - _number_agents: int, _fps: int, _time_step: float, _simulation_time: float, @@ -428,17 +429,15 @@ def init_and_run_simulation( _trajectory_path.stem + "_motivation.csv" ) logging.info(f"{motivation_file = }") - simulation = init_simulation(_data, _time_step, _fps, _trajectory_path) + simulation = init_simulation( + _data, _time_step, _fps, _trajectory_path, from_file=True + ) a_ped, d_ped, a_wall, d_wall, a_ped_min, a_ped_max, d_ped_min, d_ped_max = ( parse_velocity_init_parameters(_data) ) agent_parameters_list, exit_positions = create_agent_parameters(_data, simulation) - # positions = init_positions(_data, _number_agents) - positions_file = _data["init_positions_file"] - print("parsed json file: ", _data["init_positions_file"]) - positions = read_positions_from_csv(file_path=positions_file) - logging.info(f"Number of Agents {len(positions)}") - # positions = read_positions_from_csv(file_path="debug.csv") + + positions, num_agents = get_agent_positions(_data) ped_ids = distribute_and_add_agents( simulation=simulation, agent_parameters_list=agent_parameters_list, @@ -482,12 +481,10 @@ def start_simulation(config_path: str, output_path: str) -> float: data = json.load(f) fps = parse_fps(data) time_step = parse_time_step(data) - number_agents = parse_number_agents(data) simulation_time = parse_simulation_time(data) dummy = "" if fps and time_step: evac_time = init_and_run_simulation( - number_agents, fps, time_step, simulation_time, @@ -552,3 +549,4 @@ def main( if __name__ == "__main__": typer.run(main) +