#! python3 # Ramp-A P3-1: follow the P3 hook angle (user decision 2026-10-27: drawing r135 looks wrong). # angle = P3 angle = c/r = 141/60 rad (134.65 deg); arc length c = 165 (drawing) -> r = 165 / (141/60) = 70.21; d = 150 (drawing); b = 2137, a = 200 kept. # Source: ramp-A G5_수정5 -> ramp-A G5_수정6_20261026 (new name) import sys, os, json, math, collections, traceback sys.path.insert(0, r"C:\Users\User\AppData\Local\PierApp\jobs\c1_work") import c1_core import Rhino import Rhino.Geometry as rg from Rhino.Geometry import Arc, ArcCurve, LineCurve, PolyCurve, Point3d, Vector3d, Transform, Brep, PipeCapMode from c1_core import BASE, required_rc DATE_TXT = "2026-10-27" SRC = os.path.join(BASE, "Ramp-A교P1", "ramp-A G5_수정5_20261026.3dm") DST = os.path.join(BASE, "Ramp-A교P1", "ramp-A G5_수정6_20261026.3dm") OUT = r"C:\Users\User\AppData\Local\PierApp\jobs\c1_work\c1_p31_angle.json" THETA = 141.0 / 60.0 # P3 hook angle (rad) C_ARC, D_TAIL = 165.0, 150.0 R_NEW = C_ARC / THETA res = {} def robust_pipe(curve, d, tol): for fit, atol in ((True, tol), (False, tol), (True, 0.01), (True, 0.1)): rr = Brep.CreatePipe(curve, d / 2.0, False, PipeCapMode.Flat, fit, atol, Rhino.RhinoMath.ToRadians(1.0)) if rr and len(rr) == 1 and rr[0].IsSolid: vol = rg.VolumeMassProperties.Compute(rr[0]).Volume if abs(vol / (math.pi * (d / 2.0) ** 2 * curve.GetLength()) - 1.0) <= 0.005: return rr[0] return None def rebuild(c): n = c.SegmentCount segs = [c.SegmentCurve(i).DuplicateCurve() for i in range(n)] hook, tail = segs[-2], segs[-1] ok, arc = hook.TryGetArc() if n != 5 or not ok or hook.IsLinear() or not tail.IsLinear(): return None S = hook.PointAtStart T0 = Vector3d(hook.TangentAtStart) T0.Unitize() u = arc.Center - S u.Unitize() axis = arc.Plane.ZAxis center = S + u * R_NEW E = Point3d(S) E.Transform(Transform.Rotation(THETA, axis, center)) a2 = Arc(S, T0, E) if not a2.IsValid: return None ac = ArcCurve(a2) T1 = Vector3d(ac.TangentAtEnd) T1.Unitize() pc = PolyCurve() for s in segs[:-2]: pc.Append(s) pc.Append(ac) pc.Append(LineCurve(E, E + T1 * D_TAIL)) return pc try: doc = Rhino.RhinoDoc.OpenHeadless(SRC) tol = doc.ModelAbsoluteTolerance st = Rhino.DocObjects.ObjectEnumeratorSettings() st.HiddenObjects = True; st.LockedObjects = True; st.NormalObjects = True lay = {l.Index: l.FullPath for l in doc.Layers} res["objects_before"] = doc.Objects.Count breps = collections.defaultdict(list) curves = [] for o in doc.Objects.GetObjectList(st): g = o.Geometry L = lay.get(o.Attributes.LayerIndex, "") if isinstance(g, Brep) and "철근" in L: breps[o.Attributes.Name].append(o) elif isinstance(g, rg.Curve) and "중심선" in L and o.Attributes.GetUserString("mark") == "P3-1": curves.append(o) stat = collections.Counter() sample = None req, d = required_rc("H16") for o in curves: a = o.Attributes c = o.Geometry nb = breps.get(a.Name.replace("-RC-", "-R-"), []) if len(nb) != 1 or not isinstance(c, PolyCurve): stat["unexpected"] += 1 continue pc = rebuild(c) if pc is None: stat["rebuild_failed"] += 1 continue pipe = robust_pipe(pc, d, tol) if pipe is None: stat["pipe_fail"] += 1 continue cid, bid = o.Id, nb[0].Id if not (doc.Objects.Replace(cid, pc) and doc.Objects.Replace(bid, pipe)): stat["replace_failed"] += 1 continue for oid in (cid, bid): ro = doc.Objects.FindId(oid) at = ro.Attributes.Duplicate() old = at.GetUserString("hook_fix") or "" at.SetUserString("hook_fix", (old + " | " if old else "") + "hook angle follows P3 (%.2f deg): r %.2f, arc length 165, d 150 (drawing r135 looks wrong - user, %s)" % (math.degrees(THETA), R_NEW, DATE_TXT)) doc.Objects.ModifyAttributes(ro, at, True) if sample is None: ok2, arcn = pc.SegmentCurve(3).TryGetArc() sample = {"name": a.Name, "r": round(arcn.Radius, 3), "angle": round(math.degrees(arcn.Angle), 3), "arc_len": round(arcn.Radius * arcn.Angle, 2), "tail": round(pc.SegmentCurve(4).GetLength(), 2), "len_before": round(c.GetLength(), 1), "len_after": round(pc.GetLength(), 1)} stat["done"] += 1 res["stat"] = dict(stat) res["sample"] = sample doc.Strings.SetString("수정일", DATE_TXT) prev = doc.Strings.GetValue("수정내용") or "" doc.Strings.SetString("수정내용", (prev + " | " if prev else "") + "P3-1 hook angle follows P3 (134.65 deg), r 70.21, c 165, d 150") res["objects_after"] = doc.Objects.Count res["saved"] = bool(doc.WriteFile(DST, Rhino.FileIO.FileWriteOptions())) res["out"] = DST 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)