Improve visualizations
|
|
@ -49,7 +49,7 @@ def main() -> None:
|
||||||
print("Failed to route.")
|
print("Failed to route.")
|
||||||
|
|
||||||
# 5. Visualize
|
# 5. Visualize
|
||||||
fig, ax = plot_routing_results(results, [obstacle], bounds)
|
fig, ax = plot_routing_results(results, [obstacle], bounds, netlist=netlist)
|
||||||
fig.savefig("examples/simple_route.png")
|
fig.savefig("examples/simple_route.png")
|
||||||
print("Saved plot to examples/simple_route.png")
|
print("Saved plot to examples/simple_route.png")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ def main() -> None:
|
||||||
print(f" {nid}: valid={res.is_valid}, collisions={res.collisions}")
|
print(f" {nid}: valid={res.is_valid}, collisions={res.collisions}")
|
||||||
|
|
||||||
# 5. Visualize
|
# 5. Visualize
|
||||||
fig, ax = plot_routing_results(results, [], bounds)
|
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
|
||||||
fig.savefig("examples/congestion.png")
|
fig.savefig("examples/congestion.png")
|
||||||
print("Saved plot to examples/congestion.png")
|
print("Saved plot to examples/congestion.png")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,16 +59,18 @@ def main() -> None:
|
||||||
print("Failed to route secondary net.")
|
print("Failed to route secondary net.")
|
||||||
|
|
||||||
# 5. Visualize
|
# 5. Visualize
|
||||||
# Combine results for plotting
|
# Combine results and netlists for plotting
|
||||||
all_results = {**results1, **results2}
|
all_results = {**results1, **results2}
|
||||||
|
all_netlists = {**netlist_phase1, **netlist_phase2}
|
||||||
|
|
||||||
# Note: 'critical_net' is now in engine.static_obstacles internally,
|
# Note: 'critical_net' is now in engine.static_obstacles internally,
|
||||||
# but for visualization we plot it from the result object to see it clearly.
|
# but for visualization we plot it from the result object to see it clearly.
|
||||||
# We pass an empty list for 'static_obstacles' to plot_routing_results
|
# We pass an empty list for 'static_obstacles' to plot_routing_results
|
||||||
# because we want to see the path colored, not grayed out as an obstacle.
|
# because we want to see the path colored, not grayed out as an obstacle.
|
||||||
|
|
||||||
fig, ax = plot_routing_results(all_results, [], bounds)
|
fig, ax = plot_routing_results(all_results, [], bounds, netlist=all_netlists)
|
||||||
fig.savefig("examples/locked.png")
|
fig.savefig("examples/locked.png")
|
||||||
|
|
||||||
print("Saved plot to examples/locked.png")
|
print("Saved plot to examples/locked.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ def main() -> None:
|
||||||
print(f"{nid}: {status}, collisions={res.collisions}")
|
print(f"{nid}: {status}, collisions={res.collisions}")
|
||||||
|
|
||||||
# 6. Visualize
|
# 6. Visualize
|
||||||
fig, ax = plot_routing_results(results, [], bounds)
|
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
|
||||||
fig.savefig("examples/sbends_radii.png")
|
fig.savefig("examples/sbends_radii.png")
|
||||||
print("Saved plot to examples/sbends_radii.png")
|
print("Saved plot to examples/sbends_radii.png")
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 28 KiB |
|
|
@ -3,12 +3,14 @@ from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from matplotlib.axes import Axes
|
from matplotlib.axes import Axes
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
from shapely.geometry import Polygon
|
from shapely.geometry import Polygon
|
||||||
|
|
||||||
|
from inire.geometry.primitives import Port
|
||||||
from inire.router.pathfinder import RoutingResult
|
from inire.router.pathfinder import RoutingResult
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -16,6 +18,7 @@ def plot_routing_results(
|
||||||
results: dict[str, RoutingResult],
|
results: dict[str, RoutingResult],
|
||||||
static_obstacles: list[Polygon],
|
static_obstacles: list[Polygon],
|
||||||
bounds: tuple[float, float, float, float],
|
bounds: tuple[float, float, float, float],
|
||||||
|
netlist: dict[str, tuple[Port, Port]] | None = None,
|
||||||
) -> tuple[Figure, Axes]:
|
) -> tuple[Figure, Axes]:
|
||||||
"""Plot obstacles and routed paths using matplotlib."""
|
"""Plot obstacles and routed paths using matplotlib."""
|
||||||
fig, ax = plt.subplots(figsize=(10, 10))
|
fig, ax = plt.subplots(figsize=(10, 10))
|
||||||
|
|
@ -34,7 +37,8 @@ def plot_routing_results(
|
||||||
color = "red" # Highlight failing nets
|
color = "red" # Highlight failing nets
|
||||||
|
|
||||||
label_added = False
|
label_added = False
|
||||||
for comp in res.path:
|
for j, comp in enumerate(res.path):
|
||||||
|
# 1. Plot geometry
|
||||||
for poly in comp.geometry:
|
for poly in comp.geometry:
|
||||||
# Handle both Polygon and MultiPolygon (e.g. from SBend)
|
# Handle both Polygon and MultiPolygon (e.g. from SBend)
|
||||||
geoms = [poly] if hasattr(poly, "exterior") else poly.geoms
|
geoms = [poly] if hasattr(poly, "exterior") else poly.geoms
|
||||||
|
|
@ -43,6 +47,26 @@ def plot_routing_results(
|
||||||
ax.fill(x, y, alpha=0.7, fc=color, ec="black", label=net_id if not label_added else "")
|
ax.fill(x, y, alpha=0.7, fc=color, ec="black", label=net_id if not label_added else "")
|
||||||
label_added = True
|
label_added = True
|
||||||
|
|
||||||
|
# 2. Plot subtle port orientation arrow for internal ports
|
||||||
|
# (Every segment's end_port except possibly the last one if it matches target)
|
||||||
|
p = comp.end_port
|
||||||
|
rad = np.radians(p.orientation)
|
||||||
|
u = np.cos(rad)
|
||||||
|
v = np.sin(rad)
|
||||||
|
|
||||||
|
# Internal ports get smaller, narrower, semi-transparent arrows
|
||||||
|
ax.quiver(p.x, p.y, u, v, color="black", scale=40, width=0.003, alpha=0.3, pivot="tail", zorder=4)
|
||||||
|
|
||||||
|
# 3. Plot main arrows for netlist ports (if provided)
|
||||||
|
if netlist and net_id in netlist:
|
||||||
|
start_p, target_p = netlist[net_id]
|
||||||
|
for p in [start_p, target_p]:
|
||||||
|
rad = np.radians(p.orientation)
|
||||||
|
u = np.cos(rad)
|
||||||
|
v = np.sin(rad)
|
||||||
|
# Netlist ports get prominent arrows
|
||||||
|
ax.quiver(p.x, p.y, u, v, color="black", scale=25, width=0.005, pivot="tail", zorder=6)
|
||||||
|
|
||||||
ax.set_xlim(bounds[0], bounds[2])
|
ax.set_xlim(bounds[0], bounds[2])
|
||||||
ax.set_ylim(bounds[1], bounds[3])
|
ax.set_ylim(bounds[1], bounds[3])
|
||||||
ax.set_aspect("equal")
|
ax.set_aspect("equal")
|
||||||
|
|
@ -51,5 +75,5 @@ def plot_routing_results(
|
||||||
handles, labels = ax.get_legend_handles_labels()
|
handles, labels = ax.get_legend_handles_labels()
|
||||||
if labels:
|
if labels:
|
||||||
ax.legend()
|
ax.legend()
|
||||||
plt.grid(True)
|
ax.grid(alpha=0.6)
|
||||||
return fig, ax
|
return fig, ax
|
||||||
|
|
|
||||||