# encoding: UTF-8
# 하판 하면 사다리꼴 돌출 2개 제거 (불리언 금지 / 면 삭제 + 구멍 메움 방식)
m = Sketchup.active_model
g = m.entities.grep(Sketchup::Group).find { |e| e.name == '조립부원판_20260919' }
raise "하판 없음" if g.nil?
tr  = g.transformation
itr = tr.inverse

# 하면 평면 (전역)
best=nil; ba=0.0
g.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 }
TOLU = 0.02.mm   # 평면 위/아래 판정 허용오차
DEEP = 0.5.mm    # '확실히 아래' 기준

below = []
g.entities.grep(Sketchup::Face).each do |f|
  vs = f.vertices.map { |v| v.position.transform(tr) }
  next if vs.empty?
  allb = vs.all? { |p| p.z <= zf.call(p.x,p.y) + TOLU }
  deep = vs.any? { |p| p.z <  zf.call(p.x,p.y) - DEEP }
  below << f if allb && deep
end
puts "삭제대상 면 수=#{below.size}"
below.each do |f|
  b=Geom::BoundingBox.new; f.vertices.each{|v| b.add(v.position.transform(tr))}
  puts "  area=%.0fmm2 n=(%.3f,%.3f,%.3f) x %.1f..%.1f y %.1f..%.1f z %.2f..%.2f" %
    [f.area*645.16, f.normal.transform(tr).x, f.normal.transform(tr).y, f.normal.transform(tr).z,
     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]
end

m.start_operation('하판 돌출 정리', true)
g.entities.erase_entities(below)
# 면 0개인 떠돌이 엣지 제거
strays = g.entities.grep(Sketchup::Edge).select { |e| e.faces.empty? }
g.entities.erase_entities(strays) unless strays.empty?
puts "떠돌이엣지 제거=#{strays.size}"

# 열린 엣지(면 1개) -> 루프 구성 -> 면 메움
open_e = g.entities.grep(Sketchup::Edge).select { |e| e.faces.size == 1 }
puts "열린엣지=#{open_e.size}"
used = {}
loops = []
open_e.each do |e0|
  next if used[e0]
  loop_e = [e0]; used[e0] = true
  v = e0.end
  start_v = e0.start
  guard = 0
  while v != start_v && guard < 5000
    guard += 1
    nxt = v.edges.find { |e| !used[e] && e.faces.size == 1 }
    break if nxt.nil?
    used[nxt] = true; loop_e << nxt
    v = (nxt.start == v) ? nxt.end : nxt.start
  end
  loops << loop_e
end
puts "루프 수=#{loops.size} (엣지수 #{loops.map{|l| l.size}.inspect})"

made = 0
loops.each do |le|
  begin
    pts = []
    le.each { |e| pts << e.start.position; pts << e.end.position }
    pts = pts.uniq { |p| [p.x.to_f.round(6), p.y.to_f.round(6), p.z.to_f.round(6)] }
    f = g.entities.add_face(le)
    made += 1 if f
  rescue Exception => ex
    puts "  add_face 실패: #{ex.class} #{ex.message}"
  end
end
puts "메운 면=#{made}"
m.commit_operation

puts "결과 solid=#{g.manifold?} vol=%.0fmm3 (예상 약 7,14x,xxx)" % (g.volume.to_f*(25.4**3))
b=g.bounds
puts "bbox x %.2f..%.2f y %.2f..%.2f z %.2f..%.2f" % [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]
cnt=0; g.entities.grep(Sketchup::Face).each{|f| cnt+=1 if f.normal.transform(tr).z < -0.05}
puts "하향면 개수=#{cnt}"
nil
