#! python3 # read-only: do Ramp-A P3 / P3-1 bars stay inside the concrete? (before = 수정2 with the original hooks, after = 수정5) import sys, os, json, math, collections, traceback sys.path.insert(0, r"C:\Users\User\AppData\Local\PierApp\jobs\c1_work") import Rhino import Rhino.Geometry as rg from c1_core import BASE FILES = {"before(수정2)": os.path.join(BASE, "Ramp-A교P1", "ramp-A G5_수정2_20261026.3dm") if False else os.path.join(BASE, "Ramp-A교P1", "ramp-A G5_검토완료.3dm"), "after(수정5)": os.path.join(BASE, "Ramp-A교P1", "ramp-A G5_수정5_20261026.3dm")} OUT = r"C:\Users\User\AppData\Local\PierApp\jobs\c1_work\c1_protrude_check.json" res = {} try: for tag, p in FILES.items(): doc = Rhino.RhinoDoc.OpenHeadless(p) st = Rhino.DocObjects.ObjectEnumeratorSettings() st.HiddenObjects = True; st.LockedObjects = True; st.NormalObjects = True lay = {l.Index: l.FullPath for l in doc.Layers} concrete = [] names = collections.Counter() bars = {"P3": [], "P3-1": []} for o in doc.Objects.GetObjectList(st): g = o.Geometry L = lay.get(o.Attributes.LayerIndex, "") if isinstance(g, rg.Brep) and g.IsSolid and "철근" not in L and ("기둥" in L or "코핑" in L or "기초" in L or "콘크리트" in L or "말뚝" in L or "교각" in L): concrete.append((o.Attributes.Name, L, g)) names[L] += 1 if isinstance(g, rg.Curve) and "중심선" in L: m = o.Attributes.GetUserString("mark") if m in bars: bars[m].append(o) out = {"concrete_layers": dict(names), "bars": {}} for m, lst in bars.items(): nbar_out = 0 max_out_mm = 0.0 min_cover = 1e9 worst = None for o in lst: c = o.Geometry n = max(20, int(c.GetLength() / 15.0)) ts = c.DivideByCount(n, True) outside = 0 for t in ts: pt = c.PointAt(t) inside_any = False best = None for nm, L, b in concrete: if b.IsPointInside(pt, 0.01, True): inside_any = True cp = b.ClosestPoint(pt) dd = cp.DistanceTo(pt) best = dd if best is None else max(best, dd) if not inside_any: outside += 1 else: if best < min_cover: min_cover = best worst = [o.Attributes.Name, round(pt.X), round(pt.Y), round(pt.Z)] if outside: nbar_out += 1 max_out_mm = max(max_out_mm, outside * c.GetLength() / n) out["bars"][m] = {"n": len(lst), "bars_with_part_outside_concrete": nbar_out, "max_outside_length_mm": round(max_out_mm, 1), "min_centre_cover_inside_mm": round(min_cover, 1) if min_cover < 1e8 else None, "where": worst} res[tag] = out doc.Dispose() except Exception: res["error"] = traceback.format_exc() res["done"] = True json.dump(res, open(OUT, "w", encoding="utf-8"), ensure_ascii=False, indent=1)