chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환 - Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용 - pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관) - worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md) - D:\Rhino-MCP 경로 참조를 새 위치로 치환 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
964a841de1
3978 files changed
+58013356
No files matched your search
@@ -0,0 +1,33 @@
|
||||
# execute_rhino_code (IronPython 2.7) - 코핑 로컬 프레임 + 길이방향 단면 외곽 (s, z) 출력
|
||||
# 입력: COPING_ID
|
||||
import scriptcontext as sc, Rhino, math, System
|
||||
d = sc.doc
|
||||
tol = d.ModelAbsoluteTolerance
|
||||
COPING_ID = "d7b51436-d411-4ed6-be00-5af9d2058029"
|
||||
b = d.Objects.FindId(System.Guid(COPING_ID)).Geometry
|
||||
|
||||
# 1) 길이방향 각도: 수평 edge 방향 히스토그램
|
||||
angs = {}
|
||||
for e in b.Edges:
|
||||
v = e.PointAtEnd - e.PointAtStart
|
||||
if abs(v.Z) < 1 and v.Length > 1000:
|
||||
a = round(math.degrees(math.atan2(v.Y, v.X)) % 180.0, 3)
|
||||
angs[a] = angs.get(a, 0) + v.Length
|
||||
out = []
|
||||
for k in sorted(angs.keys()):
|
||||
out.append("ang %s total len %d" % (k, round(angs[k])))
|
||||
# 길이방향 = bbox 범위와 맞는 쪽 선택 (대호지교 P1: 19.105)
|
||||
ANG = 19.105
|
||||
a = math.radians(ANG)
|
||||
u = Rhino.Geometry.Vector3d(math.cos(a), math.sin(a), 0)
|
||||
c = b.GetBoundingBox(True).Center
|
||||
|
||||
# 2) 단면
|
||||
pl = Rhino.Geometry.Plane(c, u, Rhino.Geometry.Vector3d.ZAxis)
|
||||
ok, crvs, pts = Rhino.Geometry.Intersect.Intersection.BrepPlane(b, pl, tol)
|
||||
for sg in crvs[0].DuplicateSegments():
|
||||
p0 = sg.PointAtStart; p1 = sg.PointAtEnd
|
||||
out.append("%.1f,%.1f -> %.1f,%.1f" % ((p0 - c) * u, p0.Z, (p1 - c) * u, p1.Z))
|
||||
sc.sticky["frame"] = (ANG, c)
|
||||
result = "\n".join(out)
|
||||
print(result)
|
||||
@@ -0,0 +1,59 @@
|
||||
# execute_rhino_code (IronPython 2.7) - 형식 VII (C8/C10) 생성 예: 단면 오프셋 120 교점 + 고정길이 + KDS 필렛
|
||||
# 단면(대호지교 P1, s>0 쪽): 끝면 s=12100 (z9238~10738), 끝헌치 (12100,9238)->(8100,7738),
|
||||
# 바닥 z=7738, 내측헌치 (4900,7738)->(3400,8238)
|
||||
import scriptcontext as sc, Rhino, math, System
|
||||
from Rhino.Geometry import Point3d, Vector3d, Polyline, Curve, Brep, PipeCapMode
|
||||
d = sc.doc
|
||||
tol = d.ModelAbsoluteTolerance; atol = d.ModelAngleToleranceRadians
|
||||
COV = 120.0; r = 12.7; Rc = 76.2 + 12.7 # H25: 3db + db/2
|
||||
A_LEG = 630.0; D_LEN = 2331.0 # 재료표 a, d
|
||||
|
||||
# --- 2D 오프셋선 교점 ---
|
||||
sE = 12100.0 - COV # 끝면 오프셋
|
||||
dx = -4000.0; dz = -1500.0; Ln = math.sqrt(dx*dx + dz*dz)
|
||||
nx = -1500.0/Ln; nz = 4000.0/Ln # 안쪽 법선
|
||||
p0s = 12100.0 + COV*nx; p0z = 9238.0 + COV*nz
|
||||
t = (sE - p0s)/dx; Pab = (sE, p0z + t*dz)
|
||||
zf = 7738.0 + COV
|
||||
t = (zf - p0z)/dz; Pbc = (p0s + t*dx, zf)
|
||||
dx2 = -1500.0; dz2 = 500.0; L2 = math.sqrt(dx2*dx2 + dz2*dz2)
|
||||
q0s = 4900.0 + COV*500.0/L2; q0z = 7738.0 + COV*1500.0/L2
|
||||
t = (zf - q0z)/dz2; Pcd = (q0s + t*dx2, zf)
|
||||
D = (Pcd[0] + D_LEN*dx2/L2, zf + D_LEN*dz2/L2)
|
||||
A = (sE, Pab[1] + A_LEG)
|
||||
pts2 = [A, Pab, Pbc, Pcd, D] # 결과: b=4167.1, c=3158.8 (도면과 일치)
|
||||
|
||||
# --- 3D 생성 / 블록 교체 ---
|
||||
ang = math.radians(19.105)
|
||||
u = Vector3d(math.cos(ang), math.sin(ang), 0); wv = Vector3d(-math.sin(ang), math.cos(ang), 0)
|
||||
c = Point3d(480714926, 153833329.5, 9331)
|
||||
W_LIST = [-1630, -1375, -1125, -875, -625, -375, -125, 125, 375, 625, 875, 1125, 1375, 1630] # 1CYCLE (도면)
|
||||
out = []
|
||||
for nm, sg in [("C8", 1.0), ("C10", -1.0)]:
|
||||
idf = d.InstanceDefinitions.Find(nm)
|
||||
inst = None
|
||||
for o in d.Objects.FindByLayer(d.Layers[d.Layers.FindByFullPath("P1_두부_주철근_1CYCLE::" + nm + "_H25", -1)]):
|
||||
if o.ObjectType == Rhino.DocObjects.ObjectType.InstanceReference: inst = o
|
||||
ok, inv = inst.Geometry.Xform.TryGetInverse()
|
||||
olds = list(idf.GetObjects())
|
||||
# 백업
|
||||
bg = []; ba = []
|
||||
for o in olds:
|
||||
bg.append(o.Geometry.Duplicate()); ba.append(o.Attributes.Duplicate())
|
||||
if d.InstanceDefinitions.Find(nm + "_backup") is None:
|
||||
d.InstanceDefinitions.Add(nm + "_backup", "backup", Point3d.Origin, bg, ba)
|
||||
newg = []; newa = []
|
||||
i = 0
|
||||
for w in W_LIST:
|
||||
wpts = []
|
||||
for p in pts2:
|
||||
wpts.append(c + u*(sg*p[0]) + wv*w + Vector3d(0, 0, p[1] - c.Z))
|
||||
fc = Curve.CreateFilletCornersCurve(Polyline(wpts).ToPolylineCurve(), Rc, tol, atol)
|
||||
bp = Brep.CreatePipe(fc, r, False, PipeCapMode.NONE, False, tol, atol)[0]
|
||||
bp.Transform(inv)
|
||||
newg.append(bp); newa.append(olds[min(i, len(olds)-1)].Attributes.Duplicate())
|
||||
i += 1
|
||||
out.append(nm + " modify=" + str(d.InstanceDefinitions.ModifyGeometry(idf.Index, newg, newa)))
|
||||
d.Views.Redraw()
|
||||
result = "\n".join(out)
|
||||
print(result)
|
||||
@@ -0,0 +1,72 @@
|
||||
# execute_rhino_code (IronPython 2.7) - 검토: 파이프 Brep -> 중심선 복원, 치수/각도/길이/피복
|
||||
# 마크별로 나눠 실행 (타임아웃 방지). 컴프리헨션/lambda 금지 (exec 스코프 문제).
|
||||
import scriptcontext as sc, Rhino, math, System
|
||||
from Rhino.Geometry import Point3d, Vector3d, Line
|
||||
d = sc.doc
|
||||
cop = d.Objects.FindId(System.Guid("d7b51436-d411-4ed6-be00-5af9d2058029")).Geometry
|
||||
LAYER = "P1_두부_주철근_1CYCLE::C8_H25"; r = 12.7
|
||||
circ = 2*math.pi*r
|
||||
out = []
|
||||
o = None
|
||||
for ob in d.Objects.FindByLayer(d.Layers[d.Layers.FindByFullPath(LAYER, -1)]):
|
||||
o = ob
|
||||
xf = o.Geometry.Xform
|
||||
for leaf in o.InstanceDefinition.GetObjects():
|
||||
g = leaf.Geometry.Duplicate(); g.Transform(xf)
|
||||
Ltot = 0.0; segs = []
|
||||
for f in g.Faces:
|
||||
du = f.Domain(0); dv = f.Domain(1)
|
||||
c1 = f.IsoCurve(1, du.Mid); c0 = f.IsoCurve(0, dv.Mid)
|
||||
if c1.IsClosed and abs(c1.GetLength() - circ) < 2:
|
||||
ra = f.IsoCurve(0, dv.ParameterAt(0.0)); rb = f.IsoCurve(0, dv.ParameterAt(0.5))
|
||||
elif c0.IsClosed and abs(c0.GetLength() - circ) < 2:
|
||||
ra = f.IsoCurve(1, du.ParameterAt(0.0)); rb = f.IsoCurve(1, du.ParameterAt(0.5))
|
||||
else:
|
||||
continue # 캡 면
|
||||
Ltot += (ra.GetLength() + rb.GetLength())/2.0 # 중심선 전개길이
|
||||
if ra.IsLinear(0.01):
|
||||
segs.append(((ra.PointAtStart + rb.PointAtStart)/2.0, (ra.PointAtEnd + rb.PointAtEnd)/2.0))
|
||||
# 체인 정렬
|
||||
chain = [segs.pop(0)]
|
||||
while len(segs) > 0:
|
||||
best = None; i = 0
|
||||
while i < len(segs):
|
||||
a = segs[i][0]; b = segs[i][1]
|
||||
for cand in [(a, False, True), (b, True, True), (b, False, False), (a, True, False)]:
|
||||
if cand[2]: ref = chain[-1][1]
|
||||
else: ref = chain[0][0]
|
||||
dd = cand[0].DistanceTo(ref)
|
||||
if best is None or dd < best[0]: best = (dd, i, cand[1], cand[2])
|
||||
i += 1
|
||||
s_ = segs.pop(best[1])
|
||||
if best[2]: s_ = (s_[1], s_[0])
|
||||
if best[3]: chain.append(s_)
|
||||
else: chain.insert(0, s_)
|
||||
# 가상 교점 -> 재료표식 치수/각도
|
||||
pts = [chain[0][0]]; k = 0
|
||||
while k < len(chain) - 1:
|
||||
l1 = Line(chain[k][0], chain[k][1]); l2 = Line(chain[k+1][0], chain[k+1][1])
|
||||
ok, ta, tb = Rhino.Geometry.Intersect.Intersection.LineLine(l1, l2, 0.001, False)
|
||||
pts.append((l1.PointAt(ta) + l2.PointAt(tb))/2.0); k += 1
|
||||
pts.append(chain[-1][1])
|
||||
dims = []; angs = []; k = 0
|
||||
while k < len(pts) - 1:
|
||||
dims.append(round(pts[k].DistanceTo(pts[k+1]), 1)); k += 1
|
||||
k = 1
|
||||
while k < len(pts) - 1:
|
||||
angs.append(round(math.degrees(Vector3d.VectorAngle(pts[k-1] - pts[k], pts[k+1] - pts[k])), 1)); k += 1
|
||||
# 피복: 표면 격자 샘플 -> ClosestPoint (메시 정점 사용 금지)
|
||||
lm = 1e9
|
||||
for f in g.Faces:
|
||||
du = f.Domain(0); dv = f.Domain(1); i = 0
|
||||
while i <= 60:
|
||||
j = 0
|
||||
while j <= 24:
|
||||
p = f.PointAt(du.ParameterAt(i/60.0), dv.ParameterAt(j/24.0))
|
||||
dd = p.DistanceTo(cop.ClosestPoint(p))
|
||||
if dd < lm: lm = dd
|
||||
j += 1
|
||||
i += 1
|
||||
out.append("dims=%s sum=%.1f ang=%s Ldev=%.1f centerCover=%.2f" % (str(dims), sum(dims), str(angs), Ltot, lm + r))
|
||||
result = "\n".join(out)
|
||||
print(result)
|
||||
@@ -0,0 +1,83 @@
|
||||
# execute_rhino_code (IronPython 2.7) - 재료표 DXF(R12, 나중에 CP949 변환) 작성기
|
||||
# rows: (마크, 형식, 직경 or '"', 개수, [A,B,C,D,E,R,X1,X2,J], 길이m, 비고, 차이여부[, 총길이m(V형 직접지정)])
|
||||
# 저장 후 bash: iconv -f UTF-8 -t CP949 matl_utf8.dxf > "YYMMDD_철근재료표 작업중.dxf"
|
||||
import System
|
||||
UW = {"H16":1.560, "H19":2.250, "H22":3.040, "H25":3.980, "H29":5.040}
|
||||
PCT = {"H16":0.03, "H19":0.03, "H22":0.06, "H25":0.06, "H29":0.06}
|
||||
groups = [
|
||||
("H29", [("C9", "I", "H29", 14, ["8.539", "", "", "", "", "", "", "", ""], 8.539, "재료표 동일", False)]),
|
||||
# ("H25", [...]), ("H22", [...]), ("H19", [...])
|
||||
]
|
||||
X = [0,1200,2400,3600,4800,6800,8800,10800,12800,14800,16800,18800,20800,22800,24800,26400,28000,29600,31200,40000]
|
||||
RH = 480.0; HH = 960.0
|
||||
ents = []
|
||||
def L(x1, y1, x2, y2, lay="TABL-LIN", ents=ents):
|
||||
ents.append("0\nLINE\n8\n%s\n10\n%.3f\n20\n%.3f\n30\n0.0\n11\n%.3f\n21\n%.3f\n31\n0.0" % (lay, x1, y1, x2, y2))
|
||||
def T(x, y, s, h=200.0, lay="TABL-TEX", ents=ents):
|
||||
ents.append("0\nTEXT\n8\n%s\n10\n%.3f\n20\n%.3f\n30\n0.0\n40\n%.1f\n1\n%s\n7\nKOR\n72\n1\n11\n%.3f\n21\n%.3f\n31\n0.0\n73\n2" % (lay, x, y, h, s, x, y))
|
||||
def mid(i, X=X):
|
||||
return (X[i] + X[i+1])/2.0
|
||||
T(X[-1]/2.0, 1500, "철 근 재 료 표(두부보) - Rhino 모델 실측 기준 (작업중)", 560, "TITLE")
|
||||
T(1400, 300, "(SD400)")
|
||||
heads = ["번 호","형 식","직 경","개 수","A","B","C","D","E","R","X1(º)","X2(º)","J"]
|
||||
i = 0
|
||||
while i < 13:
|
||||
T(mid(i), -HH/2, heads[i]); i += 1
|
||||
top2 = [("길 이","(M)"),("총길이","(M)"),("단위중량","(KG/M)"),("총중량","(TON)"),("총중량(할증)","(TON)")]
|
||||
i = 0
|
||||
while i < 5:
|
||||
T(mid(13+i), -RH/2, top2[i][0]); T(mid(13+i), -RH*1.5, top2[i][1]); i += 1
|
||||
T(mid(18), -HH/2, "비 고 (원 재료표 대비)")
|
||||
L(X[0], 0, X[-1], 0); L(X[0], -HH, X[-1], -HH)
|
||||
for xx in X: L(xx, 0, xx, -HH)
|
||||
y = -HH
|
||||
gl = 0.0; gw = 0.0; gwh = 0.0; gwl = 0.0; gwlh = 0.0
|
||||
for dia, rows in groups:
|
||||
tlen = 0.0
|
||||
for rw in rows:
|
||||
yc = y - RH/2
|
||||
T(mid(0), yc, rw[0]); T(mid(1), yc, rw[1]); T(mid(2), yc, rw[2]); T(mid(3), yc, str(rw[3]))
|
||||
k = 0
|
||||
while k < 9:
|
||||
if rw[4][k] != "": T(mid(4+k), yc, rw[4][k])
|
||||
k += 1
|
||||
if len(rw) > 8: tl = rw[8]
|
||||
else: tl = round(rw[3]*rw[5], 3)
|
||||
tlen += tl
|
||||
T(mid(13), yc, "%.3f" % rw[5]); T(mid(14), yc, "%.3f" % tl)
|
||||
if rw[7]: T(mid(18), yc, rw[6], 200.0, "DIFF")
|
||||
else: T(mid(18), yc, rw[6])
|
||||
L(X[0], y-RH, X[-1], y-RH)
|
||||
for xx in X: L(xx, y, xx, y-RH)
|
||||
y -= RH
|
||||
w = tlen*UW[dia]/1000.0; wh = w*(1+PCT[dia]); wl = w*1.068; wlh = wl*(1+PCT[dia])
|
||||
pc = "(%d%%)" % int(round(PCT[dia]*100))
|
||||
T(mid(9), y-RH/2, "소 계"); T(mid(14), y-RH/2, "%.3f" % tlen); T(mid(15), y-RH/2, "%.3f" % UW[dia])
|
||||
T(mid(16), y-RH/2, "%.3f" % w); T(mid(17), y-RH/2, "%.3f%s" % (wh, pc))
|
||||
L(X[0], y-RH, X[-1], y-RH)
|
||||
for xx in [X[0]] + X[13:]: L(xx, y, xx, y-RH)
|
||||
y -= RH
|
||||
T(mid(9), y-RH/2, "소 계(겹이음 할증 6.80%)"); T(mid(16), y-RH/2, "%.3f" % wl); T(mid(17), y-RH/2, "%.3f%s" % (wlh, pc))
|
||||
L(X[0], y-RH, X[-1], y-RH)
|
||||
for xx in [X[0]] + X[13:]: L(xx, y, xx, y-RH)
|
||||
y -= RH
|
||||
gl += tlen; gw += round(w, 3); gwh += round(wh, 3); gwl += round(wl, 3); gwlh += round(wlh, 3)
|
||||
T(mid(9), y-RH/2, "총 계"); T(mid(14), y-RH/2, "%.3f" % gl); T(mid(16), y-RH/2, "%.3f" % gw); T(mid(17), y-RH/2, "%.3f" % gwh)
|
||||
L(X[0], y-RH, X[-1], y-RH)
|
||||
for xx in [X[0]] + X[13:]: L(xx, y, xx, y-RH)
|
||||
y -= RH
|
||||
T(mid(9), y-RH/2, "총 계(겹이음 할증 6.80%)"); T(mid(16), y-RH/2, "%.3f" % gwl); T(mid(17), y-RH/2, "%.3f" % gwlh)
|
||||
L(X[0], y-RH, X[-1], y-RH)
|
||||
for xx in [X[0]] + X[13:]: L(xx, y, xx, y-RH)
|
||||
hdr = "0\nSECTION\n2\nHEADER\n9\n$ACADVER\n1\nAC1009\n9\n$DWGCODEPAGE\n3\nANSI_949\n0\nENDSEC\n"
|
||||
tbl = "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLTYPE\n70\n1\n0\nLTYPE\n2\nCONTINUOUS\n70\n0\n3\nSolid line\n72\n65\n73\n0\n40\n0.0\n0\nENDTAB\n"
|
||||
lays = [("0",7),("TITLE",2),("TABL-LIN",8),("TABL-TEX",7),("DIFF",1),("NOTE",3)]
|
||||
tbl += "0\nTABLE\n2\nLAYER\n70\n%d\n" % len(lays)
|
||||
for lay in lays:
|
||||
tbl += "0\nLAYER\n2\n%s\n70\n0\n62\n%d\n6\nCONTINUOUS\n" % (lay[0], lay[1])
|
||||
tbl += "0\nENDTAB\n0\nTABLE\n2\nSTYLE\n70\n1\n0\nSTYLE\n2\nKOR\n70\n0\n40\n0.0\n41\n1.0\n50\n0.0\n71\n0\n42\n200.0\n3\nmalgun.ttf\n4\n\n0\nENDTAB\n0\nENDSEC\n"
|
||||
body = "0\nSECTION\n2\nENTITIES\n" + "\n".join(ents) + "\n0\nENDSEC\n0\nEOF\n"
|
||||
p = "C:\\temp\\matl_utf8.dxf" # 스크래치 경로로 변경해서 사용
|
||||
System.IO.File.WriteAllText(p, (hdr + tbl + body).replace("\n", "\r\n"), System.Text.UTF8Encoding(False))
|
||||
result = "ents=%d total=%.3fm %.3ft" % (len(ents), gl, gw)
|
||||
print(result)
|
||||
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 05_realign_base_pieces.py (대호지교 P1, 2026-10-06 검증)
|
||||
# 목적: 수직전단철근 박스(C12/C14/C16/C18 등)에서 바닥(⊔) 조각이 뚜껑(⊓) 평면에서 s 방향으로
|
||||
# 어긋난 것을 되돌린다. 피복(헌치 경사면에 수직인 거리)은 유지하려고 경사 접선 방향으로 움직이고,
|
||||
# 바닥 상단을 뚜껑 윗변 중심에서 다시 자른다(겹침 510 유지).
|
||||
# 실행: rhino_mcp execute_rhino_code (IronPython 2.7). MARK 하나씩 실행 (소켓 타임아웃 방지).
|
||||
# 주의: lambda/리스트컴프리헨션 금지(exec 스코프), f-string 금지. 결과는 JSON 파일로 쓰고 따로 읽는다.
|
||||
# 구조 가정: 마크 idef -> 스테이션 idef -> 박스 idef(리프 Brep: 뚜껑, 바닥, [연장 조각...])
|
||||
import Rhino, json, io, os, math
|
||||
import scriptcontext as sc
|
||||
doc = sc.doc
|
||||
|
||||
MARK = "C12" # C12 / C14 / C16 / C18 ...
|
||||
OX, OY = 480714926.0, 153833329.5 # 코핑 로컬 원점 (코핑 bbox 중심)
|
||||
ANG = math.atan2(4255.0, 12284.0) # 코핑 축 각도 (두 기둥 중심 연결선)
|
||||
# 헌치 경사 dz/ds (그 스테이션에서 콘크리트 밑면의 기울기): 끝단 헌치 ±0.375, 안쪽 헌치 ±1/3
|
||||
SLOPES = {"C12": -0.375, "C18": 0.375, "C14": 1.0 / 3.0, "C16": -1.0 / 3.0}
|
||||
RBAR = 11.1 # 철근 반지름 (H22)
|
||||
TOL = 0.5 # 이보다 작은 어긋남은 건너뜀
|
||||
|
||||
ca = math.cos(ANG)
|
||||
sa = math.sin(ANG)
|
||||
k = SLOPES[MARK]
|
||||
folder = os.path.dirname(doc.Path)
|
||||
out = os.path.join(folder, "fix_result_" + MARK + ".json")
|
||||
|
||||
inst = None
|
||||
for o in doc.Objects:
|
||||
g = o.Geometry
|
||||
if isinstance(g, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
if doc.Layers[o.Attributes.LayerIndex].FullPath.endswith(MARK + "_H22"):
|
||||
inst = g
|
||||
mxf = inst.Xform
|
||||
midf = doc.InstanceDefinitions.FindId(inst.ParentIdefId)
|
||||
|
||||
# 박스 idef 이름 -> 대표 인스턴스 월드 변환
|
||||
boxT = {}
|
||||
for ob in midf.GetObjects():
|
||||
og = ob.Geometry
|
||||
if not isinstance(og, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
continue
|
||||
sidf = doc.InstanceDefinitions.FindId(og.ParentIdefId)
|
||||
sxf = mxf * og.Xform
|
||||
for b in sidf.GetObjects():
|
||||
bg = b.Geometry
|
||||
if isinstance(bg, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
bn = doc.InstanceDefinitions.FindId(bg.ParentIdefId).Name
|
||||
if bn not in boxT:
|
||||
boxT[bn] = sxf * bg.Xform
|
||||
|
||||
report = []
|
||||
names = list(boxT.keys())
|
||||
names.sort()
|
||||
for bn in names:
|
||||
T = boxT[bn]
|
||||
ok, inv = T.TryGetInverse()
|
||||
bidf = doc.InstanceDefinitions.Find(bn)
|
||||
objs = bidf.GetObjects()
|
||||
geoms = []
|
||||
attrs = []
|
||||
info = [] # [s, area, bbox minZ, bbox maxZ] (월드)
|
||||
for ob in objs:
|
||||
bg = ob.Geometry
|
||||
amp = Rhino.Geometry.AreaMassProperties.Compute(bg)
|
||||
c = amp.Centroid
|
||||
c.Transform(T)
|
||||
s = (c.X - OX) * ca + (c.Y - OY) * sa
|
||||
w = bg.Duplicate()
|
||||
w.Transform(T)
|
||||
bbox = w.GetBoundingBox(True)
|
||||
info.append([s, bg.GetArea(), bbox.Min.Z, bbox.Max.Z])
|
||||
geoms.append(bg.Duplicate())
|
||||
attrs.append(ob.Attributes.Duplicate()) # ColorFromParent 보존
|
||||
# 면적 큰 2개 = 뚜껑/바닥 (연장 조각은 작다). 뚜껑 = bbox 최저 z가 더 높은 쪽
|
||||
i1 = -1
|
||||
i2 = -1
|
||||
for i in range(len(info)):
|
||||
if i1 < 0 or info[i][1] > info[i1][1]:
|
||||
i2 = i1
|
||||
i1 = i
|
||||
elif i2 < 0 or info[i][1] > info[i2][1]:
|
||||
i2 = i
|
||||
if info[i1][2] > info[i2][2]:
|
||||
lid = i1
|
||||
base = i2
|
||||
else:
|
||||
lid = i2
|
||||
base = i1
|
||||
dev = info[base][0] - info[lid][0]
|
||||
row = {"box": bn, "n": len(info), "dev_before": round(dev, 3)}
|
||||
if abs(dev) <= TOL:
|
||||
row["action"] = "skip"
|
||||
report.append(row)
|
||||
continue
|
||||
bkname = bn + "_bk1006b" # 백업 idef
|
||||
if doc.InstanceDefinitions.Find(bkname) is None:
|
||||
bl = []
|
||||
al = []
|
||||
for ob in objs:
|
||||
bl.append(ob.Geometry.Duplicate())
|
||||
al.append(ob.Attributes.Duplicate())
|
||||
doc.InstanceDefinitions.Add(bkname, "backup before s-realign", Rhino.Geometry.Point3d.Origin, bl, al)
|
||||
ds = -dev
|
||||
dz = k * ds # 경사 접선 방향 이동 -> 수직 피복 유지
|
||||
v = Rhino.Geometry.Vector3d(ca * ds, sa * ds, dz)
|
||||
v.Transform(inv) # 월드 이동벡터 -> idef 로컬
|
||||
ztop = info[lid][3] - RBAR # 뚜껑 윗변 중심 z (월드)
|
||||
pl = Rhino.Geometry.Plane(Rhino.Geometry.Point3d(0.0, 0.0, ztop), Rhino.Geometry.Vector3d.ZAxis)
|
||||
pl.Transform(inv)
|
||||
newgeoms = []
|
||||
for i in range(len(geoms)):
|
||||
if abs(info[i][0] - info[lid][0]) > TOL: # 뚜껑 평면에서 벗어난 조각만 이동
|
||||
m = geoms[i]
|
||||
m.Translate(v)
|
||||
chk = m.Duplicate()
|
||||
chk.Transform(T)
|
||||
if chk.GetBoundingBox(True).Max.Z > ztop + 0.05:
|
||||
tr = m.Trim(pl, 0.01) # +Z 쪽 제거
|
||||
if tr is not None and len(tr) > 0:
|
||||
m = tr[0]
|
||||
newgeoms.append(m)
|
||||
else:
|
||||
newgeoms.append(geoms[i])
|
||||
doc.InstanceDefinitions.ModifyGeometry(bidf.Index, newgeoms, attrs) # 3-인자: 속성 보존
|
||||
row["action"] = "fixed"
|
||||
row["dz"] = round(dz, 3)
|
||||
report.append(row)
|
||||
doc.Views.Redraw()
|
||||
txt = json.dumps(report)
|
||||
f = io.open(out, "w", encoding="utf-8")
|
||||
try:
|
||||
f.write(txt)
|
||||
except TypeError:
|
||||
f.write(txt.decode("utf-8"))
|
||||
f.close()
|
||||
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 06_flip_hooks.py (대호지교 P1, 2026-10-06 검증)
|
||||
# 목적: 수평전단철근(VIII: 직선 + 양끝 135° 수평 갈고리) 중 폭방향 특정 위치(|t|≈TARGET_T)의 철근만
|
||||
# 자기 축을 기준으로 거울 반전해서 갈고리 방향을 반대로 뒤집는다 (길이 불변).
|
||||
# 실행: execute_rhino_code, MARKS 한 번에 돌려도 되지만 개수가 EXPECTED와 다르면 수정하지 않고 보고만 한다.
|
||||
# 구조 가정: 마크 idef(C20/C22/C24)의 리프 Brep = 철근 1본, 인스턴스 변환은 보통 단위행렬(리프가 월드 좌표).
|
||||
import Rhino, json, io, os, math
|
||||
import scriptcontext as sc
|
||||
doc = sc.doc
|
||||
|
||||
OX, OY = 480714926.0, 153833329.5
|
||||
ANG = math.atan2(4255.0, 12284.0)
|
||||
TARGET_T = 650.0 # 대상 철근의 |t| (centroid 기준, 갈고리 때문에 축에서 ~2mm 벗어남)
|
||||
T_BAND = 40.0
|
||||
EXPECTED = {"C20": 8, "C22": 10, "C24": 12} # 위치 2곳 x 단 수 x 구역 수 (불일치 시 중단)
|
||||
|
||||
ca = math.cos(ANG)
|
||||
sa = math.sin(ANG)
|
||||
folder = os.path.dirname(doc.Path)
|
||||
res = {}
|
||||
plan = {}
|
||||
es = Rhino.DocObjects.ObjectEnumeratorSettings()
|
||||
es.HiddenObjects = True # 꺼진 레이어 객체도 열거 (기본값은 제외함!)
|
||||
es.NormalObjects = True
|
||||
es.LockedObjects = True
|
||||
for mk in EXPECTED:
|
||||
inst = None
|
||||
for o in doc.Objects.GetObjectList(es):
|
||||
g = o.Geometry
|
||||
if isinstance(g, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
if doc.Layers[o.Attributes.LayerIndex].FullPath.endswith(mk + "_H16"):
|
||||
inst = g
|
||||
T = inst.Xform
|
||||
ok, inv = T.TryGetInverse()
|
||||
idf = doc.InstanceDefinitions.FindId(inst.ParentIdefId)
|
||||
objs = idf.GetObjects()
|
||||
sel = []
|
||||
for idx in range(len(objs)):
|
||||
w = objs[idx].Geometry.Duplicate()
|
||||
w.Transform(T)
|
||||
c = Rhino.Geometry.AreaMassProperties.Compute(w).Centroid
|
||||
t = -(c.X - OX) * sa + (c.Y - OY) * ca
|
||||
if abs(abs(t) - TARGET_T) < T_BAND:
|
||||
sel.append(idx)
|
||||
plan[mk] = [T, inv, idf, objs, sel]
|
||||
res[mk] = {"selected": len(sel), "expected": EXPECTED[mk]}
|
||||
good = True
|
||||
for mk in EXPECTED:
|
||||
if res[mk]["selected"] != EXPECTED[mk]:
|
||||
good = False
|
||||
res["all_counts_match"] = good
|
||||
if good:
|
||||
for mk in EXPECTED:
|
||||
T = plan[mk][0]
|
||||
inv = plan[mk][1]
|
||||
idf = plan[mk][2]
|
||||
objs = plan[mk][3]
|
||||
sel = plan[mk][4]
|
||||
bk = mk + "_bk1006c"
|
||||
if doc.InstanceDefinitions.Find(bk) is None:
|
||||
bl = []
|
||||
al = []
|
||||
for ob in objs:
|
||||
bl.append(ob.Geometry.Duplicate())
|
||||
al.append(ob.Attributes.Duplicate())
|
||||
doc.InstanceDefinitions.Add(bk, "backup before hook flip", Rhino.Geometry.Point3d.Origin, bl, al)
|
||||
newg = []
|
||||
attrs = []
|
||||
for idx in range(len(objs)):
|
||||
attrs.append(objs[idx].Attributes.Duplicate())
|
||||
bg = objs[idx].Geometry
|
||||
if idx not in sel:
|
||||
newg.append(bg.Duplicate())
|
||||
continue
|
||||
w = bg.Duplicate()
|
||||
w.Transform(T)
|
||||
cen = w.GetBoundingBox(True).Center
|
||||
# 철근 중간 s에서 s-수직 평면으로 자르면 직선부 단면 원 -> 그 중심이 철근 축 위의 점
|
||||
plane = Rhino.Geometry.Plane(cen, Rhino.Geometry.Vector3d(ca, sa, 0.0))
|
||||
curves = Rhino.Geometry.Intersect.Intersection.BrepPlane(w, plane, 0.01)[1]
|
||||
axis_pt = Rhino.Geometry.AreaMassProperties.Compute(curves[0]).Centroid
|
||||
nrm = Rhino.Geometry.Vector3d(-sa, ca, 0.0) # 폭방향 t
|
||||
w.Transform(Rhino.Geometry.Transform.Mirror(axis_pt, nrm))
|
||||
w.Flip() # 거울 반전 뒤 법선 복구
|
||||
w.Transform(inv)
|
||||
newg.append(w)
|
||||
doc.InstanceDefinitions.ModifyGeometry(idf.Index, newg, attrs)
|
||||
doc.Views.Redraw()
|
||||
f = io.open(os.path.join(folder, "flip_result.json"), "w", encoding="utf-8")
|
||||
txt = json.dumps(res)
|
||||
try:
|
||||
f.write(txt)
|
||||
except TypeError:
|
||||
f.write(txt.decode("utf-8"))
|
||||
f.close()
|
||||
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 07_ctc_extract.py (대호지교 P1, 2026-10-06 검증)
|
||||
# 목적: 철근 마크별 리프 Brep 중심점을 코핑 로컬 좌표 (s=길이방향, t=폭방향, z)로 뽑아 JSON 저장.
|
||||
# 이후 PowerShell/awk로 고유값 정렬 -> 차이 = 도면 @간격(CTC)과 대조.
|
||||
# - 주철근: 고유 t 의 차이 (폭방향 간격)
|
||||
# - 스터럽(C12~C18): 고유 s 의 차이 (길이방향 간격) - 주의: 뚜껑/바닥 조각은 s가 서로 다를 수 있으니 클러스터 시작값만 쓰지 말 것
|
||||
# - C25 등 ⊓: 고유 s (길이방향) 와 z (단 간격)
|
||||
# 실행: 마크 하나(MARKS 1~2개)씩 돌릴 것. 전체를 한 번에 하면 AreaMassProperties 때문에 소켓 타임아웃.
|
||||
# 타임아웃이 나도 스크립트는 Rhino 안에서 계속 도므로, 결과 파일이 생길 때까지 기다린다(백그라운드 until 루프).
|
||||
import Rhino, json, io, os, math
|
||||
import scriptcontext as sc
|
||||
doc = sc.doc
|
||||
|
||||
MARKS = ["C1", "C2", "C3"]
|
||||
OX, OY = 480714926.0, 153833329.5
|
||||
ANG = math.atan2(4255.0, 12284.0)
|
||||
ca = math.cos(ANG)
|
||||
sa = math.sin(ANG)
|
||||
folder = os.path.dirname(doc.Path)
|
||||
out = os.path.join(folder, "ctc_points_" + "_".join(MARKS) + ".json")
|
||||
|
||||
es = Rhino.DocObjects.ObjectEnumeratorSettings()
|
||||
es.HiddenObjects = True # 꺼진 레이어 객체 포함
|
||||
es.NormalObjects = True
|
||||
es.LockedObjects = True
|
||||
res = {}
|
||||
for o in doc.Objects.GetObjectList(es):
|
||||
g = o.Geometry
|
||||
ly = doc.Layers[o.Attributes.LayerIndex].FullPath
|
||||
if "CYCLE" not in ly:
|
||||
continue
|
||||
mk = ly.split("::")[-1].split("_")[0]
|
||||
if mk not in MARKS:
|
||||
continue
|
||||
pts = res.get(mk, [])
|
||||
leaves = []
|
||||
if isinstance(g, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
stack = [[doc.InstanceDefinitions.FindId(g.ParentIdefId), g.Xform]]
|
||||
while len(stack) > 0:
|
||||
item = stack.pop()
|
||||
for ob in item[0].GetObjects():
|
||||
og = ob.Geometry
|
||||
if isinstance(og, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
stack.append([doc.InstanceDefinitions.FindId(og.ParentIdefId), item[1] * og.Xform])
|
||||
elif isinstance(og, Rhino.Geometry.Brep):
|
||||
c = Rhino.Geometry.AreaMassProperties.Compute(og).Centroid
|
||||
c.Transform(item[1]) # 중첩 변환: 월드 = 부모 * 자식 * 점
|
||||
leaves.append(c)
|
||||
elif isinstance(g, Rhino.Geometry.Brep): # C26처럼 인스턴스가 아닌 낱개 Brep
|
||||
leaves.append(Rhino.Geometry.AreaMassProperties.Compute(g).Centroid)
|
||||
for c in leaves:
|
||||
dx = c.X - OX
|
||||
dy = c.Y - OY
|
||||
pts.append([round(dx * ca + dy * sa, 1), round(-dx * sa + dy * ca, 1), round(c.Z, 1)])
|
||||
res[mk] = pts
|
||||
txt = json.dumps(res)
|
||||
f = io.open(out, "w", encoding="utf-8")
|
||||
try:
|
||||
f.write(txt)
|
||||
except TypeError:
|
||||
f.write(txt.decode("utf-8"))
|
||||
f.close()
|
||||
@@ -0,0 +1,195 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 08_clash_check.py (대호지교 P1, 2026-10-06) -- READ ONLY: 모델을 바꾸지 않고 CSV/JSON만 쓴다.
|
||||
# 중심선 간섭 검사: 각 철근(리프 Brep)의 파이프면에서 중심선(원주 반대편 두 isocurve의 중점)을 뽑아 선분화하고,
|
||||
# RTree 로 후보를 찾아 선분-선분 최단거리 < (rA + rB) - 0.5 이면 간섭(관입 = rA + rB - 거리).
|
||||
# 같은 박스(뚜껑+바닥+연장 조각)끼리는 겹침이음 모델링이므로 제외한다.
|
||||
# 실행: execute_rhino_code (IronPython 2.7). 소켓 타임아웃이 나도 Rhino 안에서 계속 도므로 결과 파일이 생길 때까지 기다린다.
|
||||
# 주의: 함수/lambda/컴프리헨션 금지(exec 스코프). 콜백만 기본인자로 변수를 묶어 정의한다.
|
||||
import Rhino, json, io, os, math, System
|
||||
import scriptcontext as sc
|
||||
doc = sc.doc
|
||||
folder = os.path.dirname(doc.Path)
|
||||
OX, OY = 480714926.0, 153833329.5
|
||||
ANG = math.atan2(4255.0, 12284.0)
|
||||
ca = math.cos(ANG)
|
||||
sa = math.sin(ANG)
|
||||
RAD = {"C9": 14.3, "C26": 9.55}
|
||||
for m in ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C10", "C11"]:
|
||||
RAD[m] = 12.7
|
||||
for m in ["C12", "C13", "C14", "C15", "C16", "C17", "C18"]:
|
||||
RAD[m] = 11.1
|
||||
for m in ["C19", "C20", "C21", "C22", "C23", "C24", "C25"]:
|
||||
RAD[m] = 7.95
|
||||
MIN_PEN = 0.5
|
||||
|
||||
es = Rhino.DocObjects.ObjectEnumeratorSettings()
|
||||
es.HiddenObjects = True # 꺼진 레이어도 포함
|
||||
es.NormalObjects = True
|
||||
es.LockedObjects = True
|
||||
|
||||
cache = {} # 리프 id -> 로컬 중심선 폴리라인 목록 [[Point3d,...], ...]
|
||||
segs = [] # [mark, barIdx, group, p0, p1]
|
||||
bars = [] # [mark, label]
|
||||
tree = Rhino.Geometry.RTree()
|
||||
group_counter = [0]
|
||||
|
||||
# ---- collect centerline segments of every rebar mark
|
||||
for o in doc.Objects.GetObjectList(es):
|
||||
g = o.Geometry
|
||||
ly = doc.Layers[o.Attributes.LayerIndex].FullPath
|
||||
if "CYCLE" not in ly or not ly.startswith("P1_"): # P2/P10/P12 복사본(숨김 레이어)은 제외
|
||||
continue
|
||||
mk = ly.split("::")[-1].split("_")[0]
|
||||
if mk not in RAD:
|
||||
continue
|
||||
r = RAD[mk]
|
||||
circ = 2.0 * math.pi * r
|
||||
items = [] # [leaf id, brep, xform, group]
|
||||
if isinstance(g, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
stack = [[doc.InstanceDefinitions.FindId(g.ParentIdefId), g.Xform, 0, -1]]
|
||||
while len(stack) > 0:
|
||||
it = stack.pop()
|
||||
idf = it[0]
|
||||
for ob in idf.GetObjects():
|
||||
og = ob.Geometry
|
||||
if isinstance(og, Rhino.Geometry.InstanceReferenceGeometry):
|
||||
grp = it[3]
|
||||
if it[2] + 1 == 2: # 박스 인스턴스 = 한 그룹
|
||||
group_counter[0] += 1
|
||||
grp = group_counter[0]
|
||||
stack.append([doc.InstanceDefinitions.FindId(og.ParentIdefId), it[1] * og.Xform, it[2] + 1, grp])
|
||||
elif isinstance(og, Rhino.Geometry.Brep):
|
||||
grp = it[3]
|
||||
if grp < 0:
|
||||
group_counter[0] += 1
|
||||
grp = group_counter[0]
|
||||
items.append([ob.Id, og, it[1], grp])
|
||||
elif isinstance(g, Rhino.Geometry.Brep):
|
||||
group_counter[0] += 1
|
||||
items.append([o.Id, g, Rhino.Geometry.Transform.Identity, group_counter[0]])
|
||||
for it in items:
|
||||
key = str(it[0])
|
||||
if key not in cache:
|
||||
lst = []
|
||||
for f in it[1].Faces:
|
||||
du = f.Domain(0)
|
||||
dv = f.Domain(1)
|
||||
c1 = f.IsoCurve(1, du.Mid)
|
||||
c0 = f.IsoCurve(0, dv.Mid)
|
||||
ra = None
|
||||
rb = None
|
||||
along_u = True
|
||||
if c1 is not None and c1.IsClosed and abs(c1.GetLength() - circ) < 3.0:
|
||||
ra = f.IsoCurve(0, dv.ParameterAt(0.0))
|
||||
rb = f.IsoCurve(0, dv.ParameterAt(0.5))
|
||||
elif c0 is not None and c0.IsClosed and abs(c0.GetLength() - circ) < 3.0:
|
||||
along_u = False
|
||||
ra = f.IsoCurve(1, du.ParameterAt(0.0))
|
||||
rb = f.IsoCurve(1, du.ParameterAt(0.5))
|
||||
else:
|
||||
continue
|
||||
pc = ra.ToPolyline(0, 0, 0.05, 0, 0, 0.3, 0, 1.0e6, True)
|
||||
pts = []
|
||||
for i in range(pc.PointCount):
|
||||
p = pc.Point(i)
|
||||
okc, t = ra.ClosestPoint(p)
|
||||
# 중심 = 그 위치 단면 원의 중심 (v0.5 점은 NURBS 매개변수가 균등하지 않아 반대편이 아닐 수 있음)
|
||||
if along_u:
|
||||
circ_c = f.IsoCurve(1, t)
|
||||
else:
|
||||
circ_c = f.IsoCurve(0, t)
|
||||
okr, cir = circ_c.TryGetCircle(0.1)
|
||||
if okr:
|
||||
pts.append(cir.Center)
|
||||
else:
|
||||
q = rb.PointAt(t)
|
||||
pts.append(Rhino.Geometry.Point3d((p.X + q.X) / 2.0, (p.Y + q.Y) / 2.0, (p.Z + q.Z) / 2.0))
|
||||
lst.append(pts)
|
||||
cache[key] = lst
|
||||
bidx = len(bars)
|
||||
bars.append([mk, key[:8]])
|
||||
for pl in cache[key]:
|
||||
pts = []
|
||||
for p in pl:
|
||||
q = Rhino.Geometry.Point3d(p)
|
||||
q.Transform(it[2])
|
||||
pts.append(q)
|
||||
for i in range(len(pts) - 1):
|
||||
if pts[i].DistanceTo(pts[i + 1]) < 1.0e-6:
|
||||
continue
|
||||
sidx = len(segs)
|
||||
segs.append([mk, bidx, it[3], pts[i], pts[i + 1]])
|
||||
bb = Rhino.Geometry.BoundingBox([pts[i], pts[i + 1]]) # 순서 무관 (min/max 자동) - 두 점 생성자는 순서가 뒤바뀌면 무효 상자가 됨
|
||||
bb.Inflate(r + 1.0)
|
||||
tree.Insert(bb, sidx)
|
||||
|
||||
# ---- search overlapping segments
|
||||
pairs = {}
|
||||
hits = []
|
||||
cur = [0]
|
||||
|
||||
|
||||
def cb(sender, e, hits=hits, cur=cur):
|
||||
if e.Id > cur[0]:
|
||||
hits.append(e.Id)
|
||||
|
||||
|
||||
handler = System.EventHandler[Rhino.Geometry.RTreeEventArgs](cb)
|
||||
for i in range(len(segs)):
|
||||
sA = segs[i]
|
||||
ra_ = RAD[sA[0]]
|
||||
lineA = Rhino.Geometry.Line(sA[3], sA[4])
|
||||
bb = Rhino.Geometry.BoundingBox([sA[3], sA[4]])
|
||||
bb.Inflate(ra_ + 1.0)
|
||||
del hits[:]
|
||||
cur[0] = i
|
||||
tree.Search(bb, handler)
|
||||
for j in hits:
|
||||
sB = segs[j]
|
||||
if sB[1] == sA[1] or sB[2] == sA[2]:
|
||||
continue
|
||||
rb_ = RAD[sB[0]]
|
||||
d = lineA.MinimumDistanceTo(Rhino.Geometry.Line(sB[3], sB[4]))
|
||||
pen = ra_ + rb_ - d
|
||||
if pen > MIN_PEN:
|
||||
pk = (sA[1], sB[1])
|
||||
old = pairs.get(pk)
|
||||
if old is None or pen > old[0]:
|
||||
mx = (sA[3].X + sA[4].X + sB[3].X + sB[4].X) / 4.0
|
||||
my = (sA[3].Y + sA[4].Y + sB[3].Y + sB[4].Y) / 4.0
|
||||
mz = (sA[3].Z + sA[4].Z + sB[3].Z + sB[4].Z) / 4.0
|
||||
pairs[pk] = [pen, mx, my, mz]
|
||||
|
||||
# ---- write CSV (UTF-8 BOM) + summary
|
||||
rows = []
|
||||
for pk in pairs:
|
||||
v = pairs[pk]
|
||||
a = bars[pk[0]]
|
||||
b = bars[pk[1]]
|
||||
dx = v[1] - OX
|
||||
dy = v[2] - OY
|
||||
rows.append([a[0], a[1], b[0], b[1], round(v[0], 1), round(dx * ca + dy * sa, 0), round(-dx * sa + dy * ca, 0), round(v[3], 0)])
|
||||
rows.sort()
|
||||
f = io.open(os.path.join(folder, "261006_간섭재검사_목록.csv"), "w", encoding="utf-8")
|
||||
f.write(u"마크A,철근A,마크B,철근B,관입(mm),s,w,z\n")
|
||||
for r_ in rows:
|
||||
f.write(u"%s,%s,%s,%s,%s,%s,%s,%s\n" % tuple(r_))
|
||||
f.close()
|
||||
summ = {}
|
||||
for r_ in rows:
|
||||
k = r_[0] + "|" + r_[2]
|
||||
if r_[0] > r_[2]:
|
||||
k = r_[2] + "|" + r_[0]
|
||||
s_ = summ.get(k, [0, 0.0])
|
||||
s_[0] += 1
|
||||
if r_[4] > s_[1]:
|
||||
s_[1] = r_[4]
|
||||
summ[k] = s_
|
||||
res = {"bars": len(bars), "segments": len(segs), "pairs": len(rows), "by_markpair": summ}
|
||||
f = io.open(os.path.join(folder, "261006_간섭재검사_요약.json"), "w", encoding="utf-8")
|
||||
txt = json.dumps(res, ensure_ascii=False)
|
||||
try:
|
||||
f.write(txt)
|
||||
except TypeError:
|
||||
f.write(txt.decode("utf-8"))
|
||||
f.close()
|
||||
Reference in new issue
Block a user