diff --git a/cimery/crates/kernel/src/bearing.rs b/cimery/crates/kernel/src/bearing.rs index ea436dc..9bf0e80 100644 --- a/cimery/crates/kernel/src/bearing.rs +++ b/cimery/crates/kernel/src/bearing.rs @@ -7,18 +7,20 @@ pub fn build_bearing_mesh(ir: &BearingIR) -> Result { if ir.plan_length <= 0.0 || ir.plan_width <= 0.0 || ir.total_height <= 0.0 { return Err(KernelError::InvalidInput("bearing dimensions must be positive".into())); } - // Box: X=[-l/2, +l/2] centred, Y=[-h, 0] (top at Y=0 = girder soffit), Z=[0, w] - // Caller translates to girder X offset; Y=0 means bearing top sits at soffit. - let l = ir.plan_length as f32; + // 좌표계: X = 횡방향(transverse), Y = 높이(vertical, top = 0), Z = 경간방향(span). + // plan_length = 경간 방향 치수 [mm] → sweep 축(Z). + // plan_width = 횡방향 치수 [mm] → profile X 축. + // Y=0 = 거더 소핏(soffit); bearing 상부가 소핏에 밀착. + let trans_dim = ir.plan_width as f32; // 횡 방향 (profile X) + let span_dim = ir.plan_length as f32; // 경간 방향 (sweep Z) let h = ir.total_height as f32; - let w = ir.plan_width as f32; let profile = vec![ - [-l * 0.5, -h ], - [ l * 0.5, -h ], - [ l * 0.5, 0.0], - [-l * 0.5, 0.0], + [-trans_dim * 0.5, -h ], + [ trans_dim * 0.5, -h ], + [ trans_dim * 0.5, 0.0], + [-trans_dim * 0.5, 0.0], ]; - Ok(sweep::sweep_profile_flat(&profile, w)) + Ok(sweep::sweep_profile_flat(&profile, span_dim)) } #[cfg(test)] diff --git a/cimery/crates/viewer/src/bridge_scene.rs b/cimery/crates/viewer/src/bridge_scene.rs index c51dc83..3780500 100644 --- a/cimery/crates/viewer/src/bridge_scene.rs +++ b/cimery/crates/viewer/src/bridge_scene.rs @@ -171,6 +171,9 @@ pub fn build_bridge_scene(kernel: &K, p: &SceneParams) -> Result< // ── Bearings ─────────────────────────────────────────────────────────────── // 5 per abutment, one under each girder + // plan_length(350mm) = 경간 방향 → half = 175mm 으로 Z 센터링. + const BEARING_PLAN_LEN: f32 = 350.0; + const BEARING_PLAN_WID: f32 = 450.0; for &z in &[0.0_f32, span_mm] { for i in 0..n_girders { let x = (i as f32 - (n_girders as f32 - 1.0) * 0.5) * spacing; @@ -178,14 +181,15 @@ pub fn build_bridge_scene(kernel: &K, p: &SceneParams) -> Result< id: FeatureId::new(), station: if z < 1.0 { 0.0 } else { span_m }, bearing_type: BearingType::Elastomeric, - plan_length: 350.0, - plan_width: 450.0, + plan_length: BEARING_PLAN_LEN as f64, + plan_width: BEARING_PLAN_WID as f64, total_height: BEARING_H as f64, capacity_vertical: 1_500.0, }; let mut mesh = kernel.bearing_mesh(&bearing_ir)?; mesh.recolor(COL_BEARING); - parts.push(translate(mesh, x, 0.0, z - 225.0)); + // Z 중심 = 교대 위치(z). bearing mesh Z = [0, plan_length] → 오프셋 = z - plan_length/2. + parts.push(translate(mesh, x, 0.0, z - BEARING_PLAN_LEN * 0.5)); } } @@ -383,18 +387,20 @@ pub fn build_selectable_scene( out.push(FeatureMesh { mesh: deck, label: "바닥판 슬래브".into() }); // Bearings + // plan_length(350mm) = 경간 방향 → Z 센터링 오프셋 = z - 175. + const SEL_BEARING_LEN: f32 = 350.0; for &z in &[0.0_f32, span_mm] { for i in 0..n_girders { let x = (i as f32 - (n_girders as f32 - 1.0) * 0.5) * spacing; let bir = BearingIR { id: FeatureId::new(), station: if z < 1.0 { 0.0 } else { span_m }, bearing_type: BearingType::Elastomeric, - plan_length: 350.0, plan_width: 450.0, + plan_length: SEL_BEARING_LEN as f64, plan_width: 450.0, total_height: BEARING_H as f64, capacity_vertical: 1_500.0, }; let mut mesh = kernel.bearing_mesh(&bir)?; mesh.recolor(COL_BEARING); - for v in &mut mesh.vertices { v[0] += x; v[2] += z - 225.0; } + for v in &mut mesh.vertices { v[0] += x; v[2] += z - SEL_BEARING_LEN * 0.5; } let side = if z < 1.0 { "시작" } else { "종점" }; out.push(FeatureMesh { mesh, label: format!("받침 {}-{}", side, i + 1) }); } diff --git a/cimery/crates/viewer/src/lib.rs b/cimery/crates/viewer/src/lib.rs index bea7e0c..adc8703 100644 --- a/cimery/crates/viewer/src/lib.rs +++ b/cimery/crates/viewer/src/lib.rs @@ -492,6 +492,9 @@ impl RenderState { let (mn, mx) = scene_extents(&self.params); self.scene_mn = mn; self.scene_mx = mx; + // Apply 후 씬 범위에 맞게 카메라 자동 피트 (거더 높이 변경 등이 즉시 보이도록). + self.camera.zoom_extents(mn, mx); + self.update_camera(); self.dirty = false; }