# encoding: UTF-8
# 연결브라켓_L_A : 절곡1회 L, 6T, 내R9, 수평발(커버측 Ø18 원홀+M16웰드너트) + 수직날개(윈치측 장공18x30)
m = Sketchup.active_model
T=6.0; RI=9.0; RO=RI+T
X0=9013.1; LEN=244.0                 # x 9013.1..9257.1
ZF_B=230.5; ZF_T=ZF_B+T              # 발 하면=커버프레임 상면(격판 상단 230.5) 밀착
YL_O=10951.0; YL_I=YL_O-T            # 수직날개 외/내면
Y_END=YL_O-80.0                      # 발 자유단 (발 길이 80)
Z_TOP=315.0                          # 날개 상단
CY=YL_O-RO; CZ=ZF_B+RO               # 절곡 중심
HX=[9048.11, 9224.11]                # 기존 피치 176 유지
HY=(Y_END+(YL_O-RO))/2.0             # 발 원홀 y (평탄부 중앙)
HD=18.0                              # Ø18 (M16)
SZ=280.0; SW=18.0; SL=30.0           # 장공 폭18 x 길이30(수직)
NAF=24.0; NH=13.0; NBORE=17.0        # M16 웰드너트

def a2(cu,cv,r,a0,a1,seg)
  (0..seg).map{|i| a=(a0+(a1-a0)*i.to_f/seg)*Math::PI/180.0; [cu+r*Math.cos(a), cv+r*Math.sin(a)]}
end
pr = [[Y_END, ZF_B]]
pr += a2(CY,CZ,RO,270.0,360.0,8)
pr << [YL_O, Z_TOP]
pr << [YL_I, Z_TOP]
pr += a2(CY,CZ,RI,0.0,270.0,8)
pr << [Y_END, ZF_T]
cl=[]; pr.each{|p| cl << p if cl.empty? || ((p[0]-cl[-1][0]).abs>1e-6 || (p[1]-cl[-1][1]).abs>1e-6)}

m.start_operation('연결브라켓 L A', true)
par = m.entities.add_group
pl  = par.entities.add_group
f = pl.entities.add_face(cl.map{|y,z| Geom::Point3d.new(X0.mm, y.mm, z.mm)})
raise "프로파일 실패" if f.nil?
f.reverse! if f.normal.x < 0
f.pushpull(LEN.mm)
puts "L소체 solid=#{pl.manifold?} vol=%.0fmm3" % (pl.volume.to_f*(25.4**3))

cut = []
HX.each do |hx|                                   # 발 원홀 Ø18 (수직 관통)
  g = par.entities.add_group
  cp = (0...24).map{|i| a=2*Math::PI*i/24.0; Geom::Point3d.new((hx+HD/2*Math.cos(a)).mm, (HY+HD/2*Math.sin(a)).mm, (ZF_B-10).mm)}
  cf = g.entities.add_face(cp); cf.reverse! if cf.normal.z < 0; cf.pushpull(30.0.mm)
  cut << g
end
HX.each do |hx|                                   # 날개 장공 18x30 (수평 관통, 길이=수직)
  g = par.entities.add_group
  r=SW/2.0; h=(SL-SW)/2.0
  pp = a2(hx, SZ+h, r, 0.0,180.0,8) + a2(hx, SZ-h, r, 180.0,360.0,8)
  q=[]; pp.each{|p| q << p if q.empty? || ((p[0]-q[-1][0]).abs>1e-6 || (p[1]-q[-1][1]).abs>1e-6)}
  cf = g.entities.add_face(q.map{|x,z| Geom::Point3d.new(x.mm, (YL_I-10).mm, z.mm)})
  cf.reverse! if cf.normal.y < 0; cf.pushpull(30.0.mm)
  cut << g
end
cur = pl; ok = true
cut.each_with_index do |c,i|
  r = cur.subtract(c)
  if r.nil? || !r.valid? || !r.manifold? then ok=false; puts "SUBTRACT #{i} 실패"; break end
  cur = r
end
if !ok
  m.commit_operation
  puts "-- FAIL --"
else
  cur.name = '판_A'
  rc = NAF/Math.sqrt(3.0)
  HX.each_with_index do |hx,i|                    # M16 웰드너트 (발 상면에 용접: 하면은 커버프레임 밀착면이라 비움)
    ng = par.entities.add_group
    hp = (0...6).map{|k| a=(30.0+60.0*k)*Math::PI/180.0; Geom::Point3d.new((hx+rc*Math.cos(a)).mm,(HY+rc*Math.sin(a)).mm, ZF_T.mm)}
    nf = ng.entities.add_face(hp)
    bp = (0...16).map{|k| a=2*Math::PI*k/16.0; Geom::Point3d.new((hx+NBORE/2*Math.cos(a)).mm,(HY+NBORE/2*Math.sin(a)).mm, ZF_T.mm)}
    bf = ng.entities.add_face(bp); bf.erase! if bf && bf.valid?
    nf = ng.entities.grep(Sketchup::Face).max_by{|x| x.area}
    nf.reverse! if nf.normal.z < 0
    nf.pushpull(NH.mm)
    ng.name = "웰드너트_M16_A#{i+1}"
  end
  par.name = '연결브라켓_L_A_20260919'
  m.commit_operation
  b = par.bounds
  puts "A 판 solid=#{cur.manifold?} vol=%.0fmm3" % (cur.volume.to_f*(25.4**3))
  puts "A bbox x %.2f..%.2f y %.2f..%.2f z %.2f..%.2f / 서브=#{par.entities.grep(Sketchup::Group).map{|g| [g.name,g.manifold?]}.inspect}" %
    [b.min.x.to_mm,b.max.x.to_mm,b.min.y.to_mm,b.max.y.to_mm,b.min.z.to_mm,b.max.z.to_mm]
  puts "발 원홀 y=%.2f Ø%.1f / 장공 z=%.1f %gx%g / 피치 x=#{HX.inspect} / 발하면 z=%.1f" % [HY,HD,SZ,SW,SL,ZF_B]
  m.save
  puts "SAVED #{File.mtime(m.path)}"
end
nil
