import math import ezdxf import matplotlib.pyplot as plt from matplotlib.patches import Circle, Arc def render_dxf_layer_to_png( doc: object, layer_name: str, output_path: str = "layer.png", dpi: int = 300, line_width: float = 1.0, padding_ratio: float = 0.05, ): msp = doc.modelspace() fig, ax = plt.subplots() xs = [] ys = [] def update_bounds(x, y): xs.append(x) ys.append(y) for e in msp: if e.dxf.layer != layer_name: continue etype = e.dxftype() if etype == "LINE": x1, y1 = e.dxf.start.x, e.dxf.start.y x2, y2 = e.dxf.end.x, e.dxf.end.y ax.plot([x1, x2], [y1, y2], linewidth=line_width) update_bounds(x1, y1) update_bounds(x2, y2) elif etype == "LWPOLYLINE": pts = [(p[0], p[1]) for p in e.get_points()] if len(pts) >= 2: x = [p[0] for p in pts] y = [p[1] for p in pts] if e.closed: x.append(pts[0][0]) y.append(pts[0][1]) ax.plot(x, y, linewidth=line_width) for px, py in pts: update_bounds(px, py) elif etype == "POLYLINE": pts = [(v.dxf.location.x, v.dxf.location.y) for v in e.vertices] if len(pts) >= 2: x = [p[0] for p in pts] y = [p[1] for p in pts] if e.is_closed: x.append(pts[0][0]) y.append(pts[0][1]) ax.plot(x, y, linewidth=line_width) for px, py in pts: update_bounds(px, py) elif etype == "CIRCLE": cx, cy = e.dxf.center.x, e.dxf.center.y r = e.dxf.radius patch = Circle((cx, cy), r, fill=False, linewidth=line_width) ax.add_patch(patch) update_bounds(cx - r, cy - r) update_bounds(cx + r, cy + r) elif etype == "ARC": cx, cy = e.dxf.center.x, e.dxf.center.y r = e.dxf.radius start_angle = e.dxf.start_angle end_angle = e.dxf.end_angle patch = Arc( (cx, cy), width=2 * r, height=2 * r, angle=0, theta1=start_angle, theta2=end_angle, linewidth=line_width, ) ax.add_patch(patch) # バウンディング更新は簡易的に円全体で取る update_bounds(cx - r, cy - r) update_bounds(cx + r, cy + r) if not xs or not ys: raise ValueError(f"Layer '{layer_name}' に描画対象がありません") min_x, max_x = min(xs), max(xs) min_y, max_y = min(ys), max(ys) dx = max_x - min_x dy = max_y - min_y pad_x = max(dx * padding_ratio, 1e-6) pad_y = max(dy * padding_ratio, 1e-6) ax.set_xlim(min_x - pad_x, max_x + pad_x) ax.set_ylim(min_y - pad_y, max_y + pad_y) ax.set_aspect("equal", adjustable="box") ax.axis("off") plt.savefig(output_path, dpi=dpi, bbox_inches="tight", pad_inches=0) plt.close(fig) if __name__ == "__main__": render_dxf_layer_to_png( dxf_path="input.dxf", layer_name="MY_LAYER", output_path="layer.png", )