상부 구조물: - DeckSlabIR + DeckSlabBuilder + 기하학 (직사각형 슬래브 스위프) 연결부: - BearingIR + BearingBuilder (카탈로그 기반, KDS 기본값 포함) 하부 구조물: - PierIR + PierBuilder + 기하학 (다주 지원, 코핑 포함) - AbutmentIR + AbutmentBuilder + 기하학 (흉벽 + 기초 + 날개벽) core에 BearingType·PierType·ColumnShape·AbutmentType 열거형 추가 kernel: sweep.rs 공유 모듈 (sweep_profile_flat·box·prism·merge) psc_i.rs → sweep.rs 의존으로 리팩터 GeomKernel trait에 4개 메서드 추가 (상부→하부 문서화 주석) cargo test 57개 전부 통과 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
4.3 KiB
Rust
120 lines
4.3 KiB
Rust
//! Bearing (받침) Feature builder.
|
|
//!
|
|
//! Bearing is a catalogue-based Feature: select a type and verify capacity
|
|
//! rather than computing section geometry from scratch.
|
|
|
|
use cimery_core::{BearingType, FeatureError, Mm, M};
|
|
use cimery_ir::{BearingIR, FeatureId};
|
|
|
|
#[derive(Debug)]
|
|
pub struct Bearing {
|
|
pub ir: BearingIR,
|
|
}
|
|
|
|
impl Bearing {
|
|
pub fn builder() -> BearingBuilder { BearingBuilder::default() }
|
|
|
|
/// KDS 24.14.3 elastomeric bearing defaults for PSC-I girder.
|
|
pub fn elastomeric_kds() -> Result<Self, FeatureError> {
|
|
Self::builder()
|
|
.station(M(0.0))
|
|
.bearing_type(BearingType::Elastomeric)
|
|
.plan_length(Mm(350.0))
|
|
.plan_width(Mm(450.0))
|
|
.total_height(Mm(60.0))
|
|
.capacity_vertical(1500.0)
|
|
.build()
|
|
}
|
|
}
|
|
|
|
/// Builder for a Bearing Feature.
|
|
///
|
|
/// Bearings are typically selected from a catalogue.
|
|
/// Provide dimensions and capacity from the manufacturer/catalogue data.
|
|
#[derive(Default)]
|
|
pub struct BearingBuilder {
|
|
station: Option<M>,
|
|
bearing_type: Option<BearingType>,
|
|
plan_length: Option<Mm>,
|
|
plan_width: Option<Mm>,
|
|
total_height: Option<Mm>,
|
|
capacity_vertical: Option<f64>,
|
|
}
|
|
|
|
impl BearingBuilder {
|
|
/// #[param(unit="m")] Station along alignment
|
|
pub fn station(mut self, v: M) -> Self { self.station = Some(v); self }
|
|
/// #[param(enum=BearingType, default=Elastomeric)]
|
|
pub fn bearing_type(mut self, t: BearingType) -> Self { self.bearing_type = Some(t); self }
|
|
/// #[param(unit="mm", range=150.0..=800.0, default=350.0)] Along span
|
|
pub fn plan_length(mut self, v: Mm) -> Self { self.plan_length = Some(v); self }
|
|
/// #[param(unit="mm", range=150.0..=800.0, default=450.0)] Transverse
|
|
pub fn plan_width(mut self, v: Mm) -> Self { self.plan_width = Some(v); self }
|
|
/// #[param(unit="mm", range=30.0..=300.0, default=60.0)]
|
|
pub fn total_height(mut self, v: Mm) -> Self { self.total_height = Some(v); self }
|
|
/// #[param(unit="kN", range=100.0..=50_000.0)]
|
|
pub fn capacity_vertical(mut self, v: f64) -> Self { self.capacity_vertical = Some(v); self }
|
|
|
|
pub fn build(self) -> Result<Bearing, FeatureError> {
|
|
let station = self.station.ok_or_else(|| FeatureError::missing("bearing.station"))?.value();
|
|
let bearing_type = self.bearing_type.ok_or_else(|| FeatureError::missing("bearing.bearing_type"))?;
|
|
let plan_length = self.plan_length.ok_or_else(|| FeatureError::missing("bearing.plan_length"))?.value();
|
|
let plan_width = self.plan_width.ok_or_else(|| FeatureError::missing("bearing.plan_width"))?.value();
|
|
let total_height = self.total_height.ok_or_else(|| FeatureError::missing("bearing.total_height"))?.value();
|
|
let cap_v = self.capacity_vertical.ok_or_else(|| FeatureError::missing("bearing.capacity_vertical"))?;
|
|
|
|
if plan_length < 100.0 || plan_width < 100.0 {
|
|
return Err(FeatureError::validation("bearing.plan", "minimum plan dimension 100 mm"));
|
|
}
|
|
if cap_v <= 0.0 {
|
|
return Err(FeatureError::validation("bearing.capacity_vertical", "must be > 0 kN"));
|
|
}
|
|
|
|
Ok(Bearing { ir: BearingIR {
|
|
id: FeatureId::new(),
|
|
station,
|
|
bearing_type,
|
|
plan_length,
|
|
plan_width,
|
|
total_height,
|
|
capacity_vertical: cap_v,
|
|
}})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use cimery_core::BearingType;
|
|
|
|
#[test]
|
|
fn build_elastomeric() {
|
|
let b = Bearing::builder()
|
|
.station(M(100.0))
|
|
.bearing_type(BearingType::Elastomeric)
|
|
.plan_length(Mm(350.0))
|
|
.plan_width(Mm(450.0))
|
|
.total_height(Mm(60.0))
|
|
.capacity_vertical(1500.0)
|
|
.build()
|
|
.unwrap();
|
|
assert_eq!(b.ir.bearing_type, BearingType::Elastomeric);
|
|
}
|
|
|
|
#[test]
|
|
fn kds_default() {
|
|
assert!(Bearing::elastomeric_kds().is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn zero_capacity_fails() {
|
|
let e = Bearing::builder()
|
|
.station(M(0.0))
|
|
.bearing_type(BearingType::Pot)
|
|
.plan_length(Mm(400.0)).plan_width(Mm(400.0)).total_height(Mm(100.0))
|
|
.capacity_vertical(0.0)
|
|
.build().unwrap_err();
|
|
assert!(matches!(e, FeatureError::Validation { .. }));
|
|
}
|
|
}
|