# encoding: UTF-8
# ②③ 보강 A/B 재작성 : 절곡 2회 사다리꼴 트로프, 개구부가 하판을 향함(하판과 닫힌 상자 단면)
m = Sketchup.active_model
pl = m.entities.grep(Sketchup::Group).find { |e| e.name == '조립부원판_20260919' }
raise "하판 없음" if pl.nil?
tr = pl.transformation
best=nil; ba=0.0
pl.entities.grep(Sketchup::Face).each { |f| n=f.normal.transform(tr); next unless n.z<-0.05; if f.area>ba then ba=f.area; best=f end }
pa,pb,pc,pd = Geom.fit_plane_to_points(best.outer_loop.vertices.map{|v| v.position.transform(tr)})
zf = lambda { |x,y| -(pa*x + pb*y + pd)/pc }
tv = Geom::Vector3d.new(1.0, 0.0, -pa/pc); tv.normalize!
nv = Geom::Vector3d.new(-pa, -pb, -pc);    nv.normalize!
nv.reverse! if nv.z > 0

WT=100.0; WB=60.0; D=28.4; T=6.0; RI=6.0; RO=RI+T
dxs=(WT-WB)/2.0; L=Math.sqrt(dxs*dxs+D*D)
uax=dxs/L; uay=D/L                 # 좌측 경사변 방향
nax=uay;  nay=-uax                 # 좌측변의 '재료 안쪽(트로프 내부)' 법선
cv = D - RO
t  = (cv - RO*nay) / uay
cu = RO*nax + t*uax                # 좌측 절곡 원호 중심 u
cu2 = WT - cu
ang = Math.atan2(uay, uax)*180/Math::PI            # 경사변 각도(도)
th  = 180.0 - ang                                   # 외측 접점 방향각
utip = T/uay                                        # 끝단 내측점 u

def arc(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

prof  = [[0.0,0.0]]
prof += arc(cu,  cv, RO, th,        90.0, 6)
prof += arc(cu2, cv, RO, 90.0, 180.0-th, 6)
prof << [WT, 0.0]
prof << [WT-utip, 0.0]
prof += arc(cu2, cv, RI, 180.0-th, 90.0, 6)
prof += arc(cu,  cv, RI, 90.0,      th,  6)
prof << [utip, 0.0]
clean=[]; prof.each{|p| clean << p if clean.empty? || ((p[0]-clean[-1][0]).abs>1e-6 || (p[1]-clean[-1][1]).abs>1e-6)}
puts "절곡 2회 / 경사변 %.3f도 / 중심 u=%.3f,%.3f v=%.3f / 점수 %d" % [ang, cu, cu2, cv, clean.size]

old = m.entities.grep(Sketchup::Group).select{|e| e.name.to_s.start_with?('하부보강_2절곡_')}
m.start_operation('보강 A/B 재작성', true)
m.entities.erase_entities(old) unless old.empty?
made = {}
[['하부보강_2절곡_A_20260919', 8900.0], ['하부보강_2절곡_B_20260919', 9080.0]].each do |name, xa|
  org = Geom::Point3d.new(xa.mm, 10850.0.mm, zf.call(xa.mm, 10850.0.mm))
  pts = clean.map{|u,v| org.offset(tv, u.mm).offset(nv, v.mm)}
  grp = m.entities.add_group
  f = grp.entities.add_face(pts)
  raise "#{name} 면 실패" if f.nil?
  f.reverse! if f.normal.y < 0
  f.pushpull(1050.0.mm)
  grp.name = name
  made[name] = grp
end
m.commit_operation

made.each do |name, grp|
  b = grp.bounds
  gt = grp.transformation
  dmin = 9e9
  grp.entities.grep(Sketchup::Face).each{|f| f.vertices.each{|v| p=v.position.transform(gt); d=(pa*p.x+pb*p.y+pc*p.z+pd).to_f.abs; dmin=d if d<dmin }}
  puts "#{name} solid=#{grp.manifold?} faces=#{grp.entities.grep(Sketchup::Face).size} vol=%.0fmm3 bbox x %.1f..%.1f y %.1f..%.1f z %.2f..%.2f 하판밀착틈=%.6fmm" %
    [grp.volume.to_f*(25.4**3), 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, dmin.to_mm]
end
m.save
puts "SAVED #{File.mtime(m.path)}"
nil
