# encoding: UTF-8
# rot2 — 각도 정정: 주황판(SWD_04) = 0.000도 수평 / 흰판(조립부원판) = 6.445도 경사 복원
#   자세(회전)만 조정, 형상 무변경.
HB = 'E:/도진팩토리/3D스캔및티칭시스템/_자동화/inbox/_보류/_rot2_heartbeat.txt'
def hb(s)
  begin
    File.open(HB, 'a:UTF-8') { |f| f.write("[#{Time.now.strftime('%H:%M:%S')}] #{s}\n"); f.flush }
  rescue Exception
    nil
  end
end
MM = 25.4
def deg(a); (a * 180.0 / Math::PI); end
def ents_of(e); e.is_a?(Sketchup::ComponentInstance) ? e.definition.entities : e.entities; end
def collect(ent, tr, faces)
  ents_of(ent).each do |e|
    case e
    when Sketchup::Face
      pts = e.vertices.map { |v| v.position.transform(tr) }
      n = e.normal.transform(tr); n.normalize!
      faces << [pts, n, e.area * 645.16]
    when Sketchup::Group, Sketchup::ComponentInstance
      collect(e, tr * e.transformation, faces)
    end
  end
end
def top_face(obj, tr)
  fs = []
  collect(obj, tr, fs)
  fs.select { |_, n, _| n.z > 0.5 }.max_by { |_, _, a| a }
end
def face_center(pts)
  Geom::Point3d.new(pts.map { |p| p.x }.inject(:+) / pts.length,
                    pts.map { |p| p.y }.inject(:+) / pts.length,
                    pts.map { |p| p.z }.inject(:+) / pts.length)
end

m = Sketchup.active_model
out = []
hb("START")
g2 = m.entities.grep(Sketchup::Group).find { |g| g.definition.name == "그룹#2" }
won = m.entities.grep(Sketchup::Group).find { |g| g.name == "조립부원판_20260919" }
s04 = g2 ? g2.entities.grep(Sketchup::Group).find { |g| g.name == "SWD_04_t9_240x1046" } : nil
if won.nil? || s04.nil?
  out << "대상 없음 -> 중단"
  hb("ABORT")
else
  wp, wn, = top_face(won, won.transformation)
  op, on, = top_face(s04, g2.transformation * s04.transformation)
  out << "전: 흰판(조립부원판) 기울기 #{deg(Math.acos([wn.z, 1.0].min)).round(4)}도, z #{(wp.map { |p| p.z }.min*25.4).round(2)}..#{(wp.map { |p| p.z }.max*25.4).round(2)}"
  out << "전: 주황판(SWD_04) 기울기 #{deg(Math.acos([on.z, 1.0].min)).round(4)}도, z #{(op.map { |p| p.z }.min*25.4).round(2)}..#{(op.map { |p| p.z }.max*25.4).round(2)}"
  begin
    base = File.basename(m.path, '.skp'); dir = File.dirname(m.path)
    bak = File.join(dir, "#{base}.bak_#{Time.now.strftime('%Y%m%d_%H%M%S')}_rot2직전.skp")
    m.save_copy(bak)
    hb("BACKUP OK")
    m.start_operation("각도 정정: 주황 수평 / 흰판 6.445도", true)
    # 1) 흰판: 6.4452도 경사 복원 (Y축, 상면중심 피벗)
    wpivot = face_center(wp)
    won.transform!(Geom::Transformation.rotation(wpivot, Geom::Vector3d.new(0, 1, 0), 6.4452 * Math::PI / 180.0))
    hb("WHITE ROT")
    # 2) 주황판: 상면 법선을 +Z 로 (월드 회전을 그룹#2 로컬로 환산)
    opivot = face_center(op)
    ax = on.cross(Geom::Vector3d.new(0, 0, 1))
    ang = Math.acos([[on.z, 1.0].min, -1.0].max)
    if ax.length > 1e-9 && ang.abs > 1e-9
      ax.normalize!
      rw = Geom::Transformation.rotation(opivot, ax, ang)
      s04.transformation = g2.transformation.inverse * rw * g2.transformation * s04.transformation
      hb("ORANGE ROT #{deg(ang).round(4)}")
    end
    m.commit_operation
    hb("COMMIT")
    wp2, wn2, = top_face(won, won.transformation)
    op2, on2, = top_face(s04, g2.transformation * s04.transformation)
    out << "후: 흰판 기울기 #{deg(Math.acos([[wn2.z,1.0].min,-1.0].max)).round(4)}도, 상면 z #{(wp2.map { |p| p.z }.min*25.4).round(2)}..#{(wp2.map { |p| p.z }.max*25.4).round(2)}"
    out << "후: 주황판 기울기 #{deg(Math.acos([[on2.z,1.0].min,-1.0].max)).round(4)}도, 상면 z #{(op2.map { |p| p.z }.min*25.4).round(2)}..#{(op2.map { |p| p.z }.max*25.4).round(2)}"
  rescue Exception => e
    m.commit_operation rescue nil
    out << "ERR #{e.class}: #{e.message}"
    hb("ERR #{e.message}")
  end
end
puts out.join("\n")
hb("END")
"ROT2"
