# encoding: UTF-8
begin
  puts "###DZW-DROP20-EXT-20260920"
  m = Sketchup.active_model
  bk = 'E:/도진팩토리/3D스캔및티칭시스템/_자동화/autosave/BACKUP_before_drop20ext.skp'
  m.save_copy(bk)
  puts "BACKUP=#{bk}"

  drop = 20.0
  rib_c = nil
  parts = {}
  others = []
  m.active_entities.each do |e|
    next unless e.is_a?(Sketchup::Group) || e.is_a?(Sketchup::ComponentInstance)
    nm = (e.respond_to?(:name) ? e.name.to_s : '')
    rib_c = (e.bounds.min.x.to_mm + e.bounds.max.x.to_mm) / 2.0 if nm == '그룹#1_14T절곡'
    if nm == 'RJ102-0604_LH_20260918' || nm == 'RJ102-0602_RH_20260918'
      parts[nm] = e
    else
      others << [e, nm]
    end
  end
  if parts.empty? || rib_c.nil?
    puts "STOP: 대상/간살 미발견 parts=#{parts.keys.inspect} rib=#{rib_c.inspect}"
  else
    puts "간살 중심 X=#{rib_c.round(1)}"
    plan = []
    parts.each do |nm, g|
      tr = g.transformation
      verts = []
      g.entities.grep(Sketchup::Edge).each { |ed| ed.vertices.each { |v| verts << v } }
      verts.uniq!
      wp = {}
      verts.each { |v| wp[v] = v.position.transform(tr) }
      ux = verts.map { |v| wp[v].x.to_mm }.uniq.sort
      gi = 0
      gv = -1.0
      (0...(ux.length - 1)).each do |i|
        dd = ux[i + 1] - ux[i]
        if dd > gv
          gv = dd
          gi = i
        end
      end
      x_gap = ux[gi]
      x_tip = ux[0]
      crv = verts.select { |v| wp[v].x.to_mm >= x_gap - 3.0 && wp[v].x.to_mm <= x_gap + 0.01 }
      tipv = verts.select { |v| wp[v].x.to_mm <= x_tip + 0.5 }
      z_cr_lo = crv.map { |v| wp[v].z.to_mm }.min
      z_cr_hi = crv.map { |v| wp[v].z.to_mm }.max
      z_tip_lo = tipv.map { |v| wp[v].z.to_mm }.min
      z_tip_hi = tipv.map { |v| wp[v].z.to_mm }.max
      x_cr_lo = crv.select { |v| (wp[v].z.to_mm - z_cr_lo).abs < 0.05 }.map { |v| wp[v].x.to_mm }.min
      x_cr_mid = (crv.map { |v| wp[v].x.to_mm }.min + crv.map { |v| wp[v].x.to_mm }.max) / 2.0
      run0 = x_cr_lo - x_tip
      s = (rib_c - (x_cr_mid - x_cr_lo) - x_tip) / run0
      a0 = Math.atan((z_tip_lo - z_cr_lo) / run0) * 180.0 / Math::PI
      run1 = run0 * s
      a1 = Math.atan((z_tip_lo - (z_cr_lo - drop)) / run1) * 180.0 / Math::PI
      puts "-- #{nm}: tip X#{x_tip.round(1)} Z[#{z_tip_lo.round(1)},#{z_tip_hi.round(1)}] / 절곡선 X#{x_cr_mid.round(1)} Z[#{z_cr_lo.round(1)},#{z_cr_hi.round(1)}]"
      puts "   런 #{run0.round(1)} -> #{run1.round(1)} (배율 #{s.round(4)}), 절곡높이 #{(z_tip_hi - z_cr_hi).round(1)} -> #{(z_tip_hi - (z_cr_hi - drop)).round(1)}"
      puts "   경사각(예측) #{a0.round(4)} -> #{a1.round(4)}deg"
      mv = []
      vc = []
      verts.each do |v|
        x = wp[v].x.to_mm
        if x > x_gap + 0.01
          nx = x
          nz = wp[v].z.to_mm - drop
        else
          r = (x - x_tip) / run0
          nx = x_tip + (x - x_tip) * s
          nz = wp[v].z.to_mm - drop * r
        end
        next if (nx - x).abs < 1.0e-6 && (nz - wp[v].z.to_mm).abs < 1.0e-6
        w2 = Geom::Point3d.new(nx.mm, wp[v].y, nz.mm)
        mv << v
        vc << (w2.transform(tr.inverse) - v.position)
      end
      puts "   변형 정점 #{mv.length}/#{verts.length}, 면수(전)=#{g.entities.grep(Sketchup::Face).length}"
      plan << [nm, g, mv, vc, x_tip, z_tip_lo, z_tip_hi, x_cr_mid, z_cr_lo, z_cr_hi, run0, a0, s]
    end
    m.start_operation('뒤평판 -20mm + 경사면 간살까지 연장', true)
    plan.each { |a| a[1].entities.transform_by_vectors(a[2], a[3]) }
    m.commit_operation
    plan.each do |nm, g, mv, vc, x_tip, z_tip_lo, z_tip_hi, x_cr0, z_cr_lo, z_cr_hi, run0, a0, s|
      pts = []
      g.entities.grep(Sketchup::Edge).each { |ed| ed.vertices.each { |v| pts << v.position.transform(g.transformation) } }
      xs = pts.map { |p| p.x.to_mm }
      xmin = xs.min
      xmax = xs.max
      ux2 = xs.uniq.sort
      gi2 = 0
      gv2 = -1.0
      (0...(ux2.length - 1)).each do |i|
        dd = ux2[i + 1] - ux2[i]
        if dd > gv2
          gv2 = dd
          gi2 = i
        end
      end
      xg2 = ux2[gi2]
      cr2 = pts.select { |p| p.x.to_mm >= xg2 - 4.0 && p.x.to_mm <= xg2 + 0.01 }
      ntip_lo = pts.select { |p| p.x.to_mm <= xmin + 0.5 }.map { |p| p.z.to_mm }.min
      ntip_hi = pts.select { |p| p.x.to_mm <= xmin + 0.5 }.map { |p| p.z.to_mm }.max
      ncr_lo = cr2.map { |p| p.z.to_mm }.min
      ncr_hi = cr2.map { |p| p.z.to_mm }.max
      ncr_x = (cr2.map { |p| p.x.to_mm }.min + cr2.map { |p| p.x.to_mm }.max) / 2.0
      xcl = cr2.select { |p| (p.z.to_mm - ncr_lo).abs < 0.05 }.map { |p| p.x.to_mm }.min
      am = Math.atan((ntip_lo - ncr_lo) / (xcl - xmin)) * 180.0 / Math::PI
      b = g.bounds
      puts "== #{nm} 면수(후)=#{g.entities.grep(Sketchup::Face).length}"
      puts "   앞끝 X #{x_tip.round(1)}->#{xmin.round(1)} Z #{z_tip_lo.round(1)}->#{ntip_lo.round(1)} (고정확인)"
      puts "   절곡선 X #{x_cr0.round(1)}->#{ncr_x.round(1)} (간살 #{rib_c.round(1)}), Z[#{z_cr_lo.round(1)},#{z_cr_hi.round(1)}]->[#{ncr_lo.round(1)},#{ncr_hi.round(1)}]"
      puts "   절곡높이 #{(z_tip_hi - z_cr_hi).round(1)} -> #{(ntip_hi - ncr_hi).round(1)}mm"
      puts "   경사각(실측) #{a0.round(4)} -> #{am.round(4)}deg, 런 #{run0.round(1)} -> #{(xcl - xmin).round(1)}"
      puts "   뒤끝 X#{xmax.round(1)} / bbox min=#{b.min.to_a.map { |v| v.to_mm.round(1) }.inspect} max=#{b.max.to_a.map { |v| v.to_mm.round(1) }.inspect}"
      puts "   단차(jog): 경사면 X방향 #{((s - 1) * 100).round(1)}% 신장됨(핀=앞끝). 판두께(Z)·절곡R은 불변."
      ov = []
      others.each do |e, onm|
        ob = e.bounds
        ox = [ob.max.x.to_mm, b.max.x.to_mm].min - [ob.min.x.to_mm, b.min.x.to_mm].max
        oy = [ob.max.y.to_mm, b.max.y.to_mm].min - [ob.min.y.to_mm, b.min.y.to_mm].max
        oz = [ob.max.z.to_mm, b.max.z.to_mm].min - [ob.min.z.to_mm, b.min.z.to_mm].max
        next unless ox > 0.5 && oy > 0.5 && oz > 0.5
        ov << "     BBOX겹침 '#{onm}' #{ox.round(1)}x#{oy.round(1)}x#{oz.round(1)}"
      end
      puts "   bbox 겹침 #{ov.length}건"
      ov.first(10).each { |x| puts x }
    end
    ok = m.save
    puts "SAVE=#{ok.inspect} modified?=#{m.modified?.inspect}"
    puts "DONE"
  end
rescue Exception => e
  puts "EXC #{e.class}: #{e.message}"
  puts e.backtrace.first(5).join(" | ")
end
nil
