YAML Metadata
Warning:
empty or missing yaml metadata in repo card
(https://huggingface.co/docs/hub/model-cards#model-card-metadata)
import ezdxf
import matplotlib.pyplot as plt
from matplotlib.patches import Arc
import numpy as np
import math
# ============== ์ฌ์ฉ์ ์
๋ ฅ ==============
dxf_path = "plan.dxf"
# ํ์ด๋ผ์ดํธํ ๋
ธ๋ ๊ทธ๋ฃน (์ํ๋ ๋งํผ ์ถ๊ฐ)
# points: ์ฌ์ฉ์๊ฐ ์ง์ ํ ์ขํ(๋๋ต์น์ฌ๋ ์ค๋
๋จ), label์ ์ต์
selected_groups = {
"CHECK": {
"color": "red",
"points": [(100.0, 200.0), (150.2, 80.7)], # ์์ ์ขํ
"labels": ["N1", "N2"], # ์์ผ๋ฉด ์๋ ๋ฒํธ
},
"MONITOR": {
"color": "orange",
"points": [(300.0, 210.0)],
"labels": None,
},
}
snap_tol = 1.0 # ์ค๋
ํ์ฉ์ค์ฐจ(๋๋ฉด ๋จ์). ๋๋ฉด ์ค์ผ์ผ์ ๋ง์ถฐ ์กฐ์
marker_size = 8 # ๋ง์ปค ํฝ์
ํฌ๊ธฐ
label_fontsize = 6 # ๋ผ๋ฒจ ํฐํธ ํฌ๊ธฐ
# ============== DXF ๋ก๋ ==============
doc = ezdxf.readfile(dxf_path)
msp = doc.modelspace()
fig, ax = plt.subplots(figsize=(10, 10))
# ---------------------------
# ๊ณตํต ์ ํธ
# ---------------------------
def plot_segments(ax, points, closed=False, lw=0.6, color="black"):
if len(points) < 2:
return
xs, ys = zip(*points)
ax.plot(xs, ys, linewidth=lw, color=color)
if closed and (points[0] != points[-1]):
ax.plot([points[-1][0], points[0][0]],
[points[-1][1], points[0][1]], linewidth=lw, color=color)
def plot_lwpolyline(ax, e):
"""LWPOLYLINE์ bulge(ํธ)๋ฅผ ๊ทผ์ฌํ์ฌ ๊ทธ๋ฆผ."""
pts = list(e.get_points("xyb"))
if not pts:
return
approx = []
for i in range(len(pts) - 1 + int(e.closed)):
x1, y1, b1 = pts[i % len(pts)]
x2, y2, _ = pts[(i+1) % len(pts)]
p1 = np.array([x1, y1])
p2 = np.array([x2, y2])
if abs(b1) < 1e-12:
approx += [tuple(p1), tuple(p2)]
else:
delta = 4 * math.atan(b1) # ์ค์ฌ๊ฐ
chord = p2 - p1
L = np.linalg.norm(chord)
if L < 1e-12:
continue
R = (L/2) / abs(math.sin(delta/2))
mid = (p1 + p2) / 2
n = np.array([-(chord[1]), chord[0]]) / (L + 1e-12)
h = R * math.cos(delta/2)
center = mid + np.sign(b1) * h * n
a1 = math.atan2(p1[1]-center[1], p1[0]-center[0])
a2 = math.atan2(p2[1]-center[1], p2[0]-center[0])
def angle_range(a_start, a_end, ccw=True, steps=32):
if ccw:
if a_end <= a_start:
a_end += 2*math.pi
return np.linspace(a_start, a_end, steps)
else:
if a_end >= a_start:
a_end -= 2*math.pi
return np.linspace(a_start, a_end, steps)
ccw = (b1 > 0)
angles = angle_range(a1, a2, ccw=ccw, steps=max(16, int(abs(delta)*16)))
for t in angles:
approx.append((center[0] + R*math.cos(t), center[1] + R*math.sin(t)))
cleaned = []
for p in approx:
if not cleaned or (abs(cleaned[-1][0]-p[0])>1e-9 or abs(cleaned[-1][1]-p[1])>1e-9):
cleaned.append(p)
plot_segments(ax, cleaned, closed=e.closed, lw=0.6)
def draw_basic_entity(ax, ent):
"""INSERT ์ ๊ฐ๋ ๊ฐ์ ์ํฐํฐ ํฌํจ, ๊ฐ๋ณ ์ํฐํฐ๋ฅผ ๊ทธ๋ฆผ."""
t = ent.dxftype()
if t == "LINE":
x = [ent.dxf.start.x, ent.dxf.end.x]
y = [ent.dxf.start.y, ent.dxf.end.y]
ax.plot(x, y, linewidth=0.6, color="black")
elif t == "LWPOLYLINE":
plot_lwpolyline(ax, ent)
elif t == "POLYLINE":
pts = [(v.dxf.location.x, v.dxf.location.y) for v in ent.vertices]
plot_segments(ax, pts, closed=getattr(ent, "is_closed", False), lw=0.6)
elif t == "ARC":
c = ent.dxf.center; r = ent.dxf.radius
arc = Arc((c.x, c.y), width=2*r, height=2*r, angle=0,
theta1=ent.dxf.start_angle, theta2=ent.dxf.end_angle,
linewidth=0.6, color="black")
ax.add_patch(arc)
elif t == "CIRCLE":
c = ent.dxf.center; r = ent.dxf.radius
ax.add_patch(plt.Circle((c.x, c.y), r, fill=False, linewidth=0.6, color="black"))
elif t == "ELLIPSE":
center = np.array([ent.dxf.center.x, ent.dxf.center.y])
major = np.array([ent.dxf.major_axis.x, ent.dxf.major_axis.y])
ratio = ent.dxf.ratio
t0 = ent.dxf.start_param; t1 = ent.dxf.end_param
u = major
v = np.array([-major[1], major[0]])
v = v / (np.linalg.norm(v) + 1e-12) * (np.linalg.norm(major) * ratio)
ts = np.linspace(t0, t1, 200)
xs = center[0] + u[0]*np.cos(ts) + v[0]*np.sin(ts)
ys = center[1] + u[1]*np.cos(ts) + v[1]*np.sin(ts)
ax.plot(xs, ys, linewidth=0.6, color="black")
elif t == "SPLINE":
pts = ent.approximate(segments=200)
xs, ys = zip(*[(p[0], p[1]) for p in pts])
ax.plot(xs, ys, linewidth=0.6, color="black")
elif t == "TEXT":
ins = ent.dxf.insert; text = ent.dxf.text
height = ent.dxf.height if ent.dxf.height else 2.5
rot = ent.dxf.rotation if ent.dxf.hasattr("rotation") else 0.0
ax.text(ins.x, ins.y, text, fontsize=height, rotation=rot,
rotation_mode="anchor", ha="left", va="baseline", color="black")
elif t in ("MTEXT", "ATTRIB"):
ins = ent.dxf.insert
text = ent.plain_text() if t == "MTEXT" else ent.dxf.text
rot = ent.dxf.rotation if ent.dxf.hasattr("rotation") else 0.0
h = getattr(ent.dxf, "char_height", None) or getattr(ent.dxf, "height", None) or 2.5
ax.text(ins.x, ins.y, text, fontsize=h, rotation=rot,
rotation_mode="anchor", ha="left", va="top", color="black")
elif t == "HATCH":
for path in ent.paths:
if path.PATH_TYPE_EDGE:
pts = []
for edge in path.edges:
typ = edge.EDGE_TYPE
if typ == "LineEdge":
pts += [(edge.start[0], edge.start[1]), (edge.end[0], edge.end[1])]
elif typ == "ArcEdge":
cx, cy = edge.center; r = edge.radius
a0 = math.radians(edge.start_angle); a1 = math.radians(edge.end_angle)
ts = np.linspace(a0, a1, 50)
pts += [(cx + r*np.cos(t), cy + r*np.sin(t)) for t in ts]
elif typ == "EllipseEdge":
(cx, cy) = edge.center
major = np.array(edge.major_axis); ratio = edge.ratio
t0, t1 = edge.start_param, edge.end_param
u = major; v = np.array([-major[1], major[0]])
v = v / (np.linalg.norm(v)+1e-12) * (np.linalg.norm(major)*ratio)
ts = np.linspace(t0, t1, 100)
pts += [(cx + u[0]*np.cos(t) + v[0]*np.sin(t),
cy + u[1]*np.cos(t) + v[1]*np.sin(t)) for t in ts]
elif typ == "SplineEdge":
ap = edge.spline.approximate(segments=100)
pts += [(p[0], p[1]) for p in ap]
if len(pts) >= 2:
plot_segments(ax, pts, lw=0.4)
elif path.PATH_TYPE_POLYLINE:
pts = [(v[0], v[1]) for v in path.vertices]
plot_segments(ax, pts, lw=0.4)
# ---------------------------
# 1) ๊ธฐ๋ณธ ์ํฐํฐ ๊ทธ๋ฆฌ๊ธฐ(INSERT ์ ์ธ)
# ---------------------------
for e in msp:
if e.dxftype() == "INSERT":
continue
draw_basic_entity(ax, e)
# ---------------------------
# 2) ๋ธ๋ก(INSERT) ์ ๊ฐ + DIMENSION
# ---------------------------
for br in msp.query("INSERT"):
try:
for ve in br.virtual_entities():
draw_basic_entity(ax, ve)
except Exception:
continue
for dim in msp.query("DIMENSION"):
try:
dim.render()
for ve in dim.virtual_entities():
draw_basic_entity(ax, ve)
except Exception:
continue
# ---------------------------
# 3) ๋
ธ๋ ํ๋ณด ์ถ์ถ (๋์ /๋ฒํ
์ค ์ค์ฌ)
# ---------------------------
node_candidates = []
def add_node(p):
node_candidates.append((float(p[0]), float(p[1])))
# LINE ๋์
for e in msp.query("LINE"):
add_node((e.dxf.start.x, e.dxf.start.y))
add_node((e.dxf.end.x, e.dxf.end.y))
# LWPOLYLINE: ๋ฒํ
์ค ์ขํ(ํธ ์ค๊ฐ์ ๊น์ง ๋ค ๋ฃ์ผ๋ฉด ๋๋ฌด ๋ง์์ ธ์ ๋ฒํ
์ค๋ง)
for e in msp.query("LWPOLYLINE"):
for (x, y, *_) in e.get_points("xyb"):
add_node((x, y))
# POLYLINE: ๋ฒํ
์ค
for e in msp.query("POLYLINE"):
for v in e.vertices:
add_node((v.dxf.location.x, v.dxf.location.y))
# ARC/CIRCLE ์ค์ฌ์ ๋
ธ๋๋ก ์ฐ๊ณ ์ถ๋ค๋ฉด ์๋ ์ฃผ์ ํด์
# for e in msp.query("ARC"):
# add_node((e.dxf.center.x, e.dxf.center.y))
# for e in msp.query("CIRCLE"):
# add_node((e.dxf.center.x, e.dxf.center.y))
# ์ค๋ณต ์ ๊ฑฐ(๊ฒฉ์ ์ค๋
)
def snap_key(p, tol=1e-6):
return (round(p[0]/tol), round(p[1]/tol))
uniq = {}
for p in node_candidates:
k = snap_key(p, 1e-6)
if k not in uniq:
uniq[k] = p
node_candidates = list(uniq.values())
# ---------------------------
# 4) ์ ํ ๋
ธ๋ ์ค๋
& ํ์ด๋ผ์ดํธ
# ---------------------------
def find_nearest_node(pt, candidates, tol):
"""pt์ ๊ฐ์ฅ ๊ฐ๊น์ด ํ๋ณด๋ฅผ ์ฐพ๊ณ , ๊ฑฐ๋ฆฌ๊ฐ tol๋ณด๋ค ํฌ๋ฉด None."""
px, py = pt
best = None; best_d2 = None
for cx, cy in candidates:
d2 = (cx - px)**2 + (cy - py)**2
if (best_d2 is None) or (d2 < best_d2):
best_d2 = d2; best = (cx, cy)
if best is None:
return None
dist = math.sqrt(best_d2)
return best if dist <= tol else None
def draw_marker(ax, x, y, color="red", size=8, zorder=10):
# ํ๋ฉด ํฝ์
๊ณ ์ ํฌ๊ธฐ ๋ง์ปค(๋๋ฉด ์ถ์ฒ ๋ฌด๊ด)
ax.scatter([x], [y], s=size**2, c=color, marker='o', zorder=zorder, linewidths=0.5, edgecolors="black")
# ๊ทธ๋ฃน๋ณ๋ก ์ค๋
/ํ์
legend_handles = []
for gname, cfg in selected_groups.items():
color = cfg.get("color", "red")
pts = cfg.get("points", [])
labels= cfg.get("labels", None)
placed = []
for i, pt in enumerate(pts):
snapped = find_nearest_node(pt, node_candidates, snap_tol)
if snapped is None:
# ๊ฐ๊น์ด ๋
ธ๋๊ฐ ์์ผ๋ฉด ์๋ ๋๋ต ์ขํ์ ๋ง์ปค(์ ๋ค๋ฅด๊ฒ ํ์)
draw_marker(ax, pt[0], pt[1], color="gray", size=marker_size, zorder=12)
if labels:
ax.text(pt[0], pt[1], labels[i], fontsize=label_fontsize, color="gray",
ha="left", va="bottom", zorder=12)
continue
x, y = snapped
draw_marker(ax, x, y, color=color, size=marker_size, zorder=13)
if labels:
ax.text(x, y, labels[i], fontsize=label_fontsize, color=color,
ha="left", va="bottom", zorder=13)
placed.append((x, y))
# ๋ฒ๋ก์ฉ ๋๋ฏธ(์ ํ์ฌํญ)
lh = ax.scatter([], [], s=marker_size**2, c=color, marker='o', edgecolors="black", label=gname)
legend_handles.append(lh)
if legend_handles:
ax.legend(loc="upper right", fontsize=8, frameon=True)
# ---------------------------
# 5) ๋ณด๊ธฐ/์ ์ฅ
# ---------------------------
ax.set_aspect("equal")
ax.axis("off")
# ๋๋ฉด ์ ์ฒด extents ์๋ ํฌ๋กญ(์ฌ๋ฐฑ ํฌํจ)
try:
# ezdxf์ extents ๊ณ์ฐ์ ์ฐ๊ณ ์ถ๋ค๋ฉด:
# from ezdxf.addons.drawing import layout
# ext = layout.Layout(msp).bbox() # ๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์
# ์ฌ๊ธฐ์๋ ์ฐํฌ๋ก ์ถ์ :
xs, ys = [], []
for (x, y) in node_candidates:
xs.append(x); ys.append(y)
if xs and ys:
margin = 0.05 # 5% ์ฌ๋ฐฑ
xmin, xmax = min(xs), max(xs)
ymin, ymax = min(ys), max(ys)
dx = xmax - xmin; dy = ymax - ymin
ax.set_xlim(xmin - dx*margin, xmax + dx*margin)
ax.set_ylim(ymin - dy*margin, ymax + dy*margin)
except Exception:
pass
plt.savefig("plan_with_nodes.png", dpi=300, bbox_inches="tight", pad_inches=0.02)
plt.savefig("plan_with_nodes.pdf", bbox_inches="tight", pad_inches=0.02)
plt.close()
Inference Providers
NEW
This model isn't deployed by any Inference Provider.
๐
Ask for provider support