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

  pull = 56.0
  rib0 = 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 : '')
    rib0 = e.bounds.min.x.to_mm 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?
    puts "STOP: 대상 미발견"
  else
    puts "간살 시작점(실측 min X)=#{rib0 ? rib0.round(1) : 'nil'}"
    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 - 4.0 && wp[v].x.to_mm <= x_gap + 0.01 }
      cxmin = crv.map { |v| wp[v].x.to_mm }.min
      cxmax = crv.map { |v| wp[v].x.to_mm }.max
      x_cr = (cxmin + cxmax) / 2.0
      z_cr_lo = crv.map { |v| wp[v].z.to_mm }.min
      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
      tipv = verts.select { |v| wp[v].x.to_mm <= x_tip + 0.5 }
      z_tip_lo = tipv.map { |v| wp[v].z.to_mm }.min
      tgt = x_cr - pull
      s = (tgt - x_tip) / (x_cr - x_tip)
      a0 = Math.atan((z_tip_lo - z_cr_lo) / (x_cr_lo - x_tip)) * 180.0 / Math::PI
      puts "-- #{nm}: 절곡선 #{x_cr.round(1)} -> #{tgt.round(1)} (-#{pull}), 배율 #{s.round(5)}, 현재각 #{a0.round(4)}deg"
      mv = []
      vc = []
      verts.each do |v|
        x = wp[v].x.to_mm
        next if x > x_gap + 0.01
        nx = x_tip + (x - x_tip) * s
        next if (nx - x).abs < 1.0e-6
        w2 = Geom::Point3d.new(nx.mm, wp[v].y, wp[v].z)
        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, x_cr, a0]
    end
    m.start_operation('절곡선 56mm 당김(간살 시작점)', 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, x_cr0, a0|
      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
      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 }
      ncr_x = (cr2.map { |p| p.x.to_mm }.min + cr2.map { |p| p.x.to_mm }.max) / 2.0
      ncr_lo = cr2.map { |p| p.z.to_mm }.min
      xcl = cr2.select { |p| (p.z.to_mm - ncr_lo).abs < 0.05 }.map { |p| p.x.to_mm }.min
      ntip = pts.select { |p| p.x.to_mm <= xmin + 0.5 }.map { |p| p.z.to_mm }.min
      am = Math.atan((ntip - ncr_lo) / (xcl - xmin)) * 180.0 / Math::PI
      b = g.bounds
      puts "== #{nm} 면수(후)=#{g.entities.grep(Sketchup::Face).length}"
      puts "   절곡선 X #{x_cr0.round(1)} -> #{ncr_x.round(1)} (간살 시작점 #{rib0 ? rib0.round(1) : '?'}, 차 #{rib0 ? (ncr_x - rib0).round(1) : '?'}mm)"
      puts "   앞끝 X #{xmin.round(1)} Z #{ntip.round(1)} (고정확인, 이전 #{z_tip_lo.round(1)})"
      puts "   경사각(실측) #{a0.round(4)} -> #{am.round(4)}deg, 런 #{(xcl - xmin).round(1)}"
      puts "   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}"
      ov = 0
      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
        ov += 1 if ox > 0.5 && oy > 0.5 && oz > 0.5
      end
      puts "   bbox 겹침 #{ov}건"
    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
