# encoding: UTF-8
m = Sketchup.active_model
MM = 1.0/25.4
X0, X1 = 4410.0, 5440.0
ZD = 20.4                      # 기준면(낮은 쪽 = LH 레일 밑면 수평 플랫)
T = 12.0
SY0, SY1 = 7496.2, 8788.9
CY0, CY1 = 7562.2, 7695.2      # 좌 채널 (윈치 구역과 동일 단면)
YMID = 8142.55
mir = lambda{|y| 2*YMID - y}
TY0, TY1 = 7695.2, 8589.9
YB_L, YB_R = 7518.0, mir.call(7518.0)
HY1 = [7740.0, 7905.0]; HY2 = [mir.call(7905.0), mir.call(7740.0)]
HXS = [[4700.0,4850.0],[5050.0,5200.0]]

def dedup(p,t=1e-4); o=[]; p.each{|q| o<<q unless o.last && (o.last[0]-q[0]).abs<t && (o.last[1]-q[1]).abs<t}; o.pop if o.length>2 && (o.first[0]-o.last[0]).abs<t && (o.first[1]-o.last[1]).abs<t; o; end
def rrect(x0,x1,y0,y1,r,seg=8)
  p=[]; [[x1-r,y0+r,-90.0,0.0],[x1-r,y1-r,0.0,90.0],[x0+r,y1-r,90.0,180.0],[x0+r,y0+r,180.0,270.0]].each{|cx,cy,a0,a1|
    (0..seg).each{|i| a=(a0+(a1-a0)*i/seg.to_f)*Math::PI/180.0; p << [cx+r*Math.cos(a), cy+r*Math.sin(a)]}}; dedup(p)
end
def circ(cx,cy,r,n=20); (0...n).map{|i| a=2*Math::PI*i/n; [cx+r*Math.cos(a), cy+r*Math.sin(a)]}; end

# --- 기존 레일 구멍 스캔 (X 4380~5470) ---
ex = []
["RJ102-0604_LH_20260918","RJ102-0602_RH_20260918"].each do |nm|
  g = m.entities.grep(Sketchup::Group).find{|x| x.name==nm}; next unless g
  tr = g.transformation
  g.entities.grep(Sketchup::Face).each do |f|
    f.loops.each do |lp|
      next if lp.outer?
      pts = lp.vertices.map{|v| v.position.transform(tr)}
      cx = pts.map{|p| p.x}.inject(:+)/pts.length*25.4
      cy = pts.map{|p| p.y}.inject(:+)/pts.length*25.4
      next unless cx > 4380 && cx < 5470
      ex << [cx.round(1), cy.round(1)] unless ex.any?{|a,b| (a-cx).abs<1 && (b-cy).abs<1}
    end
  end
end
puts "기존 구멍 #{ex.length}개: #{ex[0,12].inspect}"

# --- 볼트 패턴 자동 배치 (피치 95, 기존 구멍 회피) ---
PITCH = 95.0; N = 11
best = nil
(0..94).each do |off|
  s = 4460.0 + off
  xs = (0...N).map{|k| s + PITCH*k}
  next if xs.last > 5410.0
  mind = 1e9
  xs.each do |x|
    [[YB_L],[YB_R]].flatten.each do |yb|
      ex.each{|hx,hy| d = Math.sqrt((x-hx)**2 + (yb-hy)**2); mind = d if d < mind}
    end
  end
  mind = 999.0 if ex.empty?
  best = [mind, xs] if best.nil? || mind > best[0]
end
BOLTX = best[1]
puts "볼트 X=#{BOLTX.map{|v| v.round(1)}.inspect} 기존구멍 최소중심거리=#{best[0].round(1)}mm (필요 18)"

cuts = []
BOLTX.each{|x| cuts << circ(x,YB_L,9.0); cuts << circ(x,YB_R,9.0)}
mcount = 0
HXS.each do |hx0,hx1|
  [HY1,HY2].each do |hy0,hy1|
    cuts << rrect(hx0,hx1,hy0,hy1,30.0)
    [hx0-25,(hx0+hx1)/2,hx1+25].each do |rx|
      [hy0-25,(hy0+hy1)/2,hy1+25].each do |ry|
        next if rx == (hx0+hx1)/2 && ry == (hy0+hy1)/2
        cuts << circ(rx,ry,6.5); mcount += 1
      end
    end
  end
end
puts "cuts=#{cuts.length} (M16 #{BOLTX.length*2}, 점검구 4, M12 #{mcount})"

begin
  m.start_operation("오일탱크하부프레임 A", true)
  root = m.entities.add_group; root.name = "오일탱크하부프레임_20260919"
  # 하판 원철판
  g = root.entities.add_group; g.name = "하판_원철판_12T"
  e = g.entities
  f = e.add_face(rrect(X0,X1,SY0,SY1,25.0).map{|x,y| Geom::Point3d.new(x*MM,y*MM,ZD*MM)})
  ma = f.area
  cuts.each{|lp| e.add_face(lp.map{|x,y| Geom::Point3d.new(x*MM,y*MM,ZD*MM)})}
  e.grep(Sketchup::Face).each{|ff| ff.erase! if ff.valid? && ff.area < ma*0.5}
  big = e.grep(Sketchup::Face).select{|ff| ff.valid?}.max_by{|ff| ff.area}
  big.pushpull((big.normal.z > 0 ? -T : T)*MM)
  puts "  하판 solid=#{g.manifold?}"
  # 상판
  g2 = root.entities.add_group; g2.name = "상판_12T"
  f2 = g2.entities.add_face(rrect(X0,X1,TY0,TY1,25.0).map{|x,y| Geom::Point3d.new(x*MM,y*MM,(ZD+88.0)*MM)})
  f2.pushpull((f2.normal.z > 0 ? T : -T)*MM)
  puts "  상판 solid=#{g2.manifold?}"
  # 사이드 채널 (윈치 구역과 동일 단면 H100 x B133 x t12)
  secL = [[CY0,0],[CY1,0],[CY1,100.0],[CY1-T,100.0],[CY1-T,T],[CY0+T,T],[CY0+T,100.0],[CY0,100.0]]
  secR = secL.map{|y,z| [mir.call(y), z]}.reverse
  [["채널_좌_H100xB133xt12",secL],["채널_우_H100xB133xt12",secR]].each do |nm,sec|
    gg = root.entities.add_group; gg.name = nm
    ff = gg.entities.add_face(sec.map{|y,z| Geom::Point3d.new(X0*MM, y*MM, (ZD+z)*MM)})
    ff.pushpull((ff.normal.x > 0 ? (X1-X0) : -(X1-X0))*MM)
    puts "  #{nm} solid=#{gg.manifold?}"
  end
  m.commit_operation
  b = root.bounds
  puts "A BBOX (#{(b.min.x*25.4).round(1)},#{(b.min.y*25.4).round(1)},#{(b.min.z*25.4).round(1)})..(#{(b.max.x*25.4).round(1)},#{(b.max.y*25.4).round(1)},#{(b.max.z*25.4).round(1)})"
rescue Exception => ex2
  m.commit_operation rescue nil
  puts "ERR #{ex2.class}: #{ex2.message}"; puts ex2.backtrace[0,3].join("\n")
end
"OIL2"
