squid_n_core/model/
wall_region.rs1use super::*;
28
29#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
32pub struct WallRegion {
33 pub id: WallRegionId,
35 #[serde(default)]
37 pub name: String,
38 #[serde(default)]
40 pub boundary: Vec<NodeId>,
41 #[serde(default)]
46 pub wall_plate_ids: Vec<WallPlateId>,
47 #[serde(default)]
49 pub posts: Vec<SecondaryMember>,
50}
51
52impl WallRegion {
53 pub fn new(id: WallRegionId, boundary: Vec<NodeId>) -> Self {
55 WallRegion {
56 id,
57 name: String::new(),
58 boundary,
59 wall_plate_ids: Vec::new(),
60 posts: Vec::new(),
61 }
62 }
63
64 pub fn boundary_coords(&self, model: &Model) -> Option<Vec<[f64; 3]>> {
66 self.boundary
67 .iter()
68 .map(|n| model.nodes.get(n.index()).map(|n| n.coord))
69 .collect()
70 }
71
72 pub fn edge_nodes(&self, k: usize) -> Option<[NodeId; 2]> {
74 let n = self.boundary.len();
75 (n >= 3 && k < n).then(|| [self.boundary[k], self.boundary[(k + 1) % n]])
76 }
77
78 pub fn reference_node(&self) -> Option<NodeId> {
80 self.boundary.first().copied()
81 }
82
83 pub fn area(&self, model: &Model) -> f64 {
86 self.boundary_coords(model)
87 .map(|pts| crate::geom::polygon::area_3d(&pts))
88 .unwrap_or(0.0)
89 }
90}
91
92impl Model {
93 pub fn wall_region(&self, id: WallRegionId) -> Option<&WallRegion> {
95 match self.wall_regions.get(id.index()) {
96 Some(r) if r.id == id => Some(r),
97 _ => self.wall_regions.iter().find(|r| r.id == id),
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::ids::NodeId;
106
107 fn model_with_nodes(pts: &[[f64; 3]]) -> Model {
108 let mut m = Model::default();
109 for (i, p) in pts.iter().enumerate() {
110 m.nodes.push(Node {
111 id: NodeId(i as u32),
112 coord: *p,
113 restraint: Default::default(),
114 mass: None,
115 story: None,
116 support_spring: None,
117 });
118 }
119 m
120 }
121
122 #[test]
123 fn test_boundary_coords_and_area() {
124 let m = model_with_nodes(&[
125 [0.0, 0.0, 0.0],
126 [4000.0, 0.0, 0.0],
127 [4000.0, 0.0, 3000.0],
128 [0.0, 0.0, 3000.0],
129 ]);
130 let r = WallRegion::new(
131 WallRegionId(0),
132 vec![NodeId(0), NodeId(1), NodeId(2), NodeId(3)],
133 );
134 let coords = r.boundary_coords(&m).expect("境界座標");
135 assert_eq!(coords.len(), 4);
136 assert!((r.area(&m) - 4000.0 * 3000.0).abs() < 1e-6);
137 assert_eq!(r.reference_node(), Some(NodeId(0)));
138 assert_eq!(r.edge_nodes(0), Some([NodeId(0), NodeId(1)]));
139 }
140}