# encoding: UTF-8
# L브라켓 A/B 최종사양: 절곡1회 L, 6T, 내R9
#   발(커버프레임측, 수평) : Ø18 원홀 x2 + 하면(안쪽) M16 웰드너트(24AF/13H)
#   날개(윈치측, 수직)     : 장공 18 x 30 (R9)
#   불리언 subtract 가 이 세션에서 '병합'으로 동작 -> 각 조각을 구멍축 방향으로 압출해 구멍을 직접 생성
m = Sketchup.active_model
Sketchup.undo   # 직전 M16 시제(깨진 판) 제거
old = m.entities.grep(Sketchup::Group).select{|g| g.name.to_s.start_with?('연결브라켓_L_')}
T=6.0; RI=9.0; RO=RI+T
ZFB=230.5; ZFT=ZFB+T; ZTAN=ZFB+RO; ZTOP=320.0
HD=18.0; SW=18.0; SL=30.0; SZ=282.0
NAF=24.0; NH=13.0; NBORE=17.0

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
def stad(cx,cy,w,l,seg)
  r=w/2.0; h=(l-w)/2.0
  pp = a2(cx,cy+h,r,0.0,180.0,seg) + a2(cx,cy-h,r,180.0,360.0,seg)
  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)}; q
end
def circ(cx,cy,d,seg); (0...seg).map{|i| a=2*Math::PI*i/seg; [cx+d/2*Math.cos(a), cy+d/2*Math.sin(a)]}; end

m.start_operation('연결브라켓 L A/B 최종', true)
m.entities.erase_entities(old) unless old.empty?
log = []
# 홀 x는 격판 SWD_02(x 9155.8~9226.6) 회피 -> 웰드너트 간섭 0
[['A', 9013.1, 9173.1, [9048.0, 9138.0],  1, 10951.0],
 ['B', 9037.7, 9175.7, [9072.7, 9140.0], -1, 11743.5]].each do |nm,x0,x1,hxs,s,YO|
  YTAN = YO - s*RO; YEND = YO - s*70.0; YI = YO - s*T
  SCY = (YTAN + YEND)/2.0
  par = m.entities.add_group

  ft = par.entities.add_group                      # 발: z축 압출 (Ø18 원홀 직접 생성)
  ry=[YEND,YTAN].sort
  ft.entities.add_face([[x0,ry[0]],[x1,ry[0]],[x1,ry[1]],[x0,ry[1]]].map{|x,y| Geom::Point3d.new(x.mm,y.mm,ZFB.mm)})
  hxs.each{|hx| hf=ft.entities.add_face(circ(hx,SCY,HD,24).map{|x,y| Geom::Point3d.new(x.mm,y.mm,ZFB.mm)}); hf.erase! if hf&&hf.valid?}
  f=ft.entities.grep(Sketchup::Face).max_by{|q| q.area}; f.reverse! if f.normal.z>0; f.pushpull(-T.mm)
  ft.name="발_#{nm}"

  lg = par.entities.add_group                      # 날개: y축 압출 (장공 18x30 직접 생성)
  lg.entities.add_face([[x0,ZTAN],[x1,ZTAN],[x1,ZTOP],[x0,ZTOP]].map{|x,z| Geom::Point3d.new(x.mm,YI.mm,z.mm)})
  hxs.each{|hx| hf=lg.entities.add_face(stad(hx,SZ,SW,SL,8).map{|x,z| Geom::Point3d.new(x.mm,YI.mm,z.mm)}); hf.erase! if hf&&hf.valid?}
  f2=lg.entities.grep(Sketchup::Face).max_by{|q| q.area}; f2.reverse! if f2.normal.y*s<0; f2.pushpull(T.mm)
  lg.name="날개_#{nm}"

  bd = par.entities.add_group                      # 절곡 R: x축 압출
  ao1 = (s>0 ? 360.0 : 180.0); ai0 = (s>0 ? 0.0 : 180.0)
  pr=[[YTAN,ZFB]] + a2(YTAN,ZTAN,RO,270.0,ao1,10) + [[YI,ZTAN]] + a2(YTAN,ZTAN,RI,ai0,270.0,10) + [[YTAN,ZFT]]
  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)}
  f3=bd.entities.add_face(cl.map{|y,z| Geom::Point3d.new(x0.mm,y.mm,z.mm)})
  raise "#{nm} 절곡부 실패" if f3.nil?
  f3.reverse! if f3.normal.x<0; f3.pushpull((x1-x0).mm)
  bd.name="절곡R_#{nm}"

  rc=NAF/Math.sqrt(3.0)                            # M16 웰드너트: 발 하면(안쪽)
  hxs.each_with_index do |hx,i|
    ng=par.entities.add_group
    ng.entities.add_face((0...6).map{|k| a=(30.0+60.0*k)*Math::PI/180.0; Geom::Point3d.new((hx+rc*Math.cos(a)).mm,(SCY+rc*Math.sin(a)).mm,ZFB.mm)})
    bf=ng.entities.add_face(circ(hx,SCY,NBORE,16).map{|x,y| Geom::Point3d.new(x.mm,y.mm,ZFB.mm)}); bf.erase! if bf&&bf.valid?
    nf=ng.entities.grep(Sketchup::Face).max_by{|q| q.area}; nf.reverse! if nf.normal.z>0; nf.pushpull(NH.mm)
    ng.name="웰드너트_M16_#{nm}#{i+1}"
  end

  par.name="연결브라켓_L_#{nm}_20260919"
  b=par.bounds
  subs=par.entities.grep(Sketchup::Group)
  log << "#{par.name} 조각solid=#{subs.map{|g| g.manifold?}.inspect} bbox x %.1f..%.1f y %.1f..%.1f z %.1f..%.1f / Ø18홀 x=#{hxs.inspect} y=%.1f / 장공 18x30 z=%.1f / 너트 z %.1f~%.1f" %
    [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,SCY,SZ,ZFB-NH,ZFB]
end
m.commit_operation
log.each{|l| puts l}
m.save
puts "SAVED #{File.mtime(m.path)} TOP=#{m.entities.count}"
nil
