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()
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support