# encoding: UTF-8
begin
  puts "###DZW-CLEAN2-20260920"
  m = Sketchup.active_model
  bk = 'E:/도진팩토리/3D스캔및티칭시스템/_자동화/autosave/BACKUP_before_clean2.skp'
  m.save_copy(bk)
  puts "BACKUP=#{bk}"
  ents = lambda { |s| s.is_a?(Sketchup::Group) ? s.entities : s.definition.entities }
  hits = []
  walk = nil
  walk = lambda do |ent, tr, path, depth|
    (ent.grep(Sketchup::Group) + ent.grep(Sketchup::ComponentInstance)).each do |s|
      nm = (s.respond_to?(:name) ? s.name.to_s : '')
      dn = s.is_a?(Sketchup::ComponentInstance) ? s.definition.name.to_s : ''
      lbl = nm.empty? ? (dn.empty? ? '(무명)' : dn) : nm
      st = tr * s.transformation
      en = ents.call(s)
      fcount = en.grep(Sketchup::Face).length
      if fcount > 0
        ps = []
        en.grep(Sketchup::Edge).each { |ed| ed.vertices.each { |v| ps << v.position.transform(st) } }
        unless ps.empty?
          xr = ps.map { |p| p.x.to_mm }.minmax
          yr = ps.map { |p| p.y.to_mm }.minmax
          inzone = xr[1] >= 3900 && xr[0] <= 4600 && yr[1] >= 7500 && yr[0] <= 8810
          hits << ["#{path}/#{lbl}", s, fcount] if inzone
        end
      end
      walk.call(en, st, "#{path}/#{lbl}", depth + 1) if depth < 4
    end
  end
  walk.call(m.entities, Geom::Transformation.new, '', 0)
  puts "커버 영역(X3900~4600, Y7500~8810) 내 면 보유 부재 #{hits.length}개"
  hits.each { |p, s, fc| puts "  #{p} 면#{fc}" }
  tot_d = 0
  tot_s = 0
  hits.each do |path, g, fc|
    next unless g.valid?
    en = ents.call(g)
    v0 = (g.respond_to?(:volume) ? g.volume : -1.0)
    edges = en.grep(Sketchup::Edge)
    rem = []
    soft = []
    edges.each do |ed|
      fs = ed.faces
      next unless fs.length == 2
      d = fs[0].normal.dot(fs[1].normal)
      d = 1.0 if d > 1.0
      d = -1.0 if d < -1.0
      ang = Math.acos(d.abs) * 180.0 / Math::PI
      if ang < 0.05
        rem << ed
      elsif ang < 20.0
        soft << ed
      end
    end
    del = 0
    if !rem.empty?
      m.start_operation('coplanar 제거', true)
      rem.each_slice(40) do |ch|
        live = ch.select { |e2| e2.valid? }
        begin
          en.erase_entities(live)
        rescue Exception
          live.each { |e2| (e2.erase! if e2.valid?) rescue nil }
        end
        del += live.length
      end
      m.commit_operation
    end
    sf = 0
    if !soft.empty?
      m.start_operation('소프트닝', true)
      soft.each do |ed|
        next unless ed.valid?
        ed.soft = true
        ed.smooth = true
        sf += 1
      end
      m.commit_operation
    end
    v1 = (g.valid? && g.respond_to?(:volume) ? g.volume : -1.0)
    dv = (v0 > 0 && v1 > 0) ? ((v1 - v0).abs / v0 * 100.0) : nil
    tot_d += del
    tot_s += sf
    puts "  '#{path.split('/').last}' 에지#{edges.length} 제거#{del} 소프트#{sf} 체적 #{v0 > 0 ? (v0 * 16387.064).round(0) : 'n/a'}->#{v1 > 0 ? (v1 * 16387.064).round(0) : 'n/a'}#{dv ? " (차#{dv.round(4)}%)" : ''}"
  end
  puts "합계: 제거 #{tot_d}개 / 소프트닝 #{tot_s}개"
  vw = m.active_view
  cam0 = vw.camera
  begin
    c = Geom::Point3d.new(4250.mm, 8150.mm, 120.mm)
    vw.camera = Sketchup::Camera.new(Geom::Point3d.new(c.x.to_f, c.y.to_f, c.z - 2000.mm), c, Geom::Vector3d.new(1, 0, 0))
    f = 'E:/도진팩토리/3D스캔및티칭시스템/_자동화/inbox/_clean2_bottom.png'
    vw.write_image(f, 1600, 1000, true)
    puts "캡처=#{f} 존재=#{File.exist?(f)}"
  rescue Exception => e3
    puts "캡처 실패 #{e3.message}"
  ensure
    vw.camera = cam0
  end
  ok = m.save
  puts "SAVE=#{ok.inspect} modified?=#{m.modified?.inspect}"
  puts "DONE"
rescue Exception => e
  puts "EXC #{e.class}: #{e.message}"
  puts e.backtrace.first(6).join(" | ")
end
nil
