27 polygons: List[Polygon],
28 rectangles: List[Rectangle] =
None,
29 title: str =
"Layout View"):
30 """Plot polygons and rectangles in a layout."""
31 fig, ax = plt.subplots(figsize=self.
figsize)
34 for i, polygon
in enumerate(polygons):
35 x_coords = [v.x
for v
in polygon.vertices] + [polygon.vertices[0].x]
36 y_coords = [v.y
for v
in polygon.vertices] + [polygon.vertices[0].y]
38 ax.plot(x_coords, y_coords,
'b-', linewidth=2, alpha=0.7)
39 ax.fill(x_coords, y_coords, alpha=0.3, color=
'lightblue')
43 ax.text(centroid.x, centroid.y, f
'P{i}',
44 ha=
'center', va=
'center', fontweight=
'bold')
48 for i, rect
in enumerate(rectangles):
49 rect_patch = patches.Rectangle(
50 (rect.x, rect.y), rect.width, rect.height,
51 linewidth=2, edgecolor=
'red', facecolor=
'lightcoral', alpha=0.3
53 ax.add_patch(rect_patch)
56 ax.text(rect.center.x, rect.center.y, f
'R{i}',
57 ha=
'center', va=
'center', fontweight=
'bold')
59 ax.set_aspect(
'equal')
60 ax.grid(
True, alpha=0.3)
68 polygons: List[Polygon],
69 analysis_results: Dict,
70 title: str =
"Layout Analysis"):
71 """Plot layout with analysis overlays."""
72 fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
79 sharp_angles = analysis_results.get(
'sharp_angles', {}).get(
'details', [])
80 for poly_id, vertex_idx, angle
in sharp_angles:
81 if poly_id < len(polygons):
82 vertex = polygons[poly_id].vertices[vertex_idx]
83 ax2.plot(vertex.x, vertex.y,
'ro', markersize=8)
84 ax2.text(vertex.x, vertex.y, f
'{angle:.1f}°',
85 xytext=(5, 5), textcoords=
'offset points',
86 fontsize=8, color=
'red')
90 narrow_regions = analysis_results.get(
'narrow_distances', {}).get(
'details', [])
91 for point1, point2, distance
in narrow_regions:
92 ax3.plot([point1.x, point2.x], [point1.y, point2.y],
93 'r-', linewidth=3, alpha=0.7)
94 mid_x = (point1.x + point2.x) / 2
95 mid_y = (point1.y + point2.y) / 2
96 ax3.text(mid_x, mid_y, f
'{distance:.2f}',
97 ha=
'center', va=
'center', fontsize=8,
98 bbox=dict(boxstyle=
'round,pad=0.2', facecolor=
'yellow', alpha=0.7))
102 intersection_points = analysis_results.get(
'intersections', {}).get(
'points', [])
103 for point
in intersection_points:
104 ax4.plot(point.x, point.y,
'rx', markersize=10, markeredgewidth=3)
111 polygons: List[Polygon] =
None,
112 title: str =
"QuadTree Structure"):
113 """Visualize quadtree structure."""
114 fig, ax = plt.subplots(figsize=self.
figsize)
118 for polygon
in polygons:
119 x_coords = [v.x
for v
in polygon.vertices] + [polygon.vertices[0].x]
120 y_coords = [v.y
for v
in polygon.vertices] + [polygon.vertices[0].y]
121 ax.plot(x_coords, y_coords,
'b-', linewidth=1, alpha=0.5)
122 ax.fill(x_coords, y_coords, alpha=0.2, color=
'lightblue')
127 ax.set_aspect(
'equal')
128 ax.grid(
True, alpha=0.3)
136 """Create a summary visualization of optimization results."""
137 fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(14, 10))
139 analysis = optimization_results[
'analysis']
142 score = optimization_results[
'optimization_score']
146 issue_types = [
'Sharp Angles',
'Narrow Distances',
'Intersections']
148 analysis[
'sharp_angles'][
'count'],
149 analysis[
'narrow_distances'][
'count'],
150 analysis[
'intersections'][
'polygon_pairs']
152 colors = [
'orange',
'red',
'darkred']
154 bars = ax2.bar(issue_types, counts, color=colors, alpha=0.7)
155 ax2.set_title(
'Issues Found')
156 ax2.set_ylabel(
'Count')
159 for bar, count
in zip(bars, counts):
160 height = bar.get_height()
161 ax2.text(bar.get_x() + bar.get_width()/2., height,
162 f
'{count}', ha=
'center', va=
'bottom')
165 if analysis[
'narrow_distances'][
'count'] > 0:
166 min_dist = analysis[
'narrow_distances'][
'minimum']
167 max_dist = analysis[
'narrow_distances'][
'maximum']
168 avg_dist = analysis[
'narrow_distances'][
'average']
170 distances = [
'Minimum',
'Average',
'Maximum']
171 values = [min_dist, avg_dist, max_dist]
173 ax3.bar(distances, values, color=
'skyblue', alpha=0.7)
174 ax3.set_title(
'Distance Statistics')
175 ax3.set_ylabel(
'Distance')
177 for bar, value
in zip(ax3.patches, values):
178 height = bar.get_height()
179 ax3.text(bar.get_x() + bar.get_width()/2., height,
180 f
'{value:.3f}', ha=
'center', va=
'bottom')
182 ax3.text(0.5, 0.5,
'No narrow distances found',
183 ha=
'center', va=
'center', transform=ax3.transAxes)
184 ax3.set_title(
'Distance Statistics')
187 suggestions = optimization_results[
'suggestions']
189 ax4.set_title(
'Optimization Suggestions')
192 suggestion_text =
'\n\n'.join([f
"• {s}" for s
in suggestions])
194 suggestion_text =
"✓ No issues found! Layout looks good."
196 ax4.text(0.05, 0.95, suggestion_text, transform=ax4.transAxes,
197 verticalalignment=
'top', fontsize=10, wrap=
True)
203 """Helper to plot polygons on a given axis."""
204 for polygon
in polygons:
205 x_coords = [v.x
for v
in polygon.vertices] + [polygon.vertices[0].x]
206 y_coords = [v.y
for v
in polygon.vertices] + [polygon.vertices[0].y]
208 ax.plot(x_coords, y_coords,
'b-', linewidth=2, alpha=0.7)
209 ax.fill(x_coords, y_coords, alpha=0.3, color=
'lightblue')
211 ax.set_aspect(
'equal')
212 ax.grid(
True, alpha=0.3)
218 """Recursively draw quadtree node boundaries."""
223 boundary = node.boundary
224 rect = patches.Rectangle(
225 (boundary.x, boundary.y), boundary.width, boundary.height,
226 linewidth=1, edgecolor=
'gray', facecolor=
'none', alpha=0.5
231 object_count = len(node.objects)
233 center = boundary.center
234 ax.text(center.x, center.y, str(object_count),
235 ha=
'center', va=
'center', fontsize=8,
236 bbox=dict(boxstyle=
'round,pad=0.2', facecolor=
'white', alpha=0.7))
240 for child
in node.children:
244 """Plot a gauge showing optimization score."""
246 theta = (score / 100) * 180
250 theta_bg = list(range(0, 181, 5))
251 x_bg = [0.8 * math.cos(math.radians(t))
for t
in theta_bg]
252 y_bg = [0.8 * math.sin(math.radians(t))
for t
in theta_bg]
253 ax.plot(x_bg, y_bg,
'lightgray', linewidth=10)
257 theta_score = list(range(0, int(theta) + 1, 5))
258 x_score = [0.8 * math.cos(math.radians(t))
for t
in theta_score]
259 y_score = [0.8 * math.sin(math.radians(t))
for t
in theta_score]
270 ax.plot(x_score, y_score, color, linewidth=10)
273 ax.text(0, -0.3, f
'{score:.1f}', ha=
'center', va=
'center',
274 fontsize=24, fontweight=
'bold')
275 ax.text(0, -0.5,
'Optimization Score', ha=
'center', va=
'center',
280 ax.set_aspect(
'equal')
282 ax.set_title(
'Layout Quality Score')
292 format: str =
'png', dpi: int = 300):
293 """Save multiple figures to files."""
294 for i, fig
in enumerate(figures):
295 filename = f
"{base_filename}_{i+1}.{format}"
296 fig.savefig(filename, format=format, dpi=dpi, bbox_inches=
'tight')
297 print(f
"Saved plot: {filename}")