forked from 1b-agent/fieldcraft-upstream
model: keep defeatures, features of the design taken out for meshing
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
e9ef7f9d4d
commit
3f0cae70a2
2 files changed
+65
-2
No files matched your search
+12
-2
@@ -87,7 +87,7 @@ pub use steps::{
|
||||
};
|
||||
pub use tie::Tie;
|
||||
pub use units::UnitSystem;
|
||||
pub use virtual_faces::{FaceMerge, FaceSplit, Stitch};
|
||||
pub use virtual_faces::{Defeature, FaceMerge, FaceSplit, Stitch};
|
||||
|
||||
/// The largest node or element label. Nastran's GRID and element ids stop at 99 999 999 (eight
|
||||
/// digits in a small field), the tightest of the three formats.
|
||||
@@ -191,6 +191,9 @@ pub struct Model {
|
||||
/// Face splits along datum planes, in the order they apply (after the merges).
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
face_splits: Vec<FaceSplit>,
|
||||
/// Features of the design taken out for meshing, in the order they were made.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
defeatures: Vec<Defeature>,
|
||||
}
|
||||
|
||||
/// A [`Model`] as stored, before it is checked.
|
||||
@@ -253,6 +256,8 @@ struct ModelData {
|
||||
stitches: Vec<Stitch>,
|
||||
#[serde(default)]
|
||||
face_splits: Vec<FaceSplit>,
|
||||
#[serde(default)]
|
||||
defeatures: Vec<Defeature>,
|
||||
}
|
||||
|
||||
impl TryFrom<ModelData> for Model {
|
||||
@@ -355,6 +360,9 @@ impl TryFrom<ModelData> for Model {
|
||||
for v in d.face_splits {
|
||||
m.add_face_split(v)?;
|
||||
}
|
||||
for v in d.defeatures {
|
||||
m.set_defeature(v)?;
|
||||
}
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
@@ -492,6 +500,7 @@ impl Model {
|
||||
face_merges: self.face_merges.clone(),
|
||||
stitches: self.stitches.clone(),
|
||||
face_splits: self.face_splits.clone(),
|
||||
defeatures: self.defeatures.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,7 +551,7 @@ impl Model {
|
||||
}
|
||||
|
||||
/// Counts of each kind of definition, for summaries.
|
||||
pub fn definition_counts(&self) -> [(&'static str, usize); 20] {
|
||||
pub fn definition_counts(&self) -> [(&'static str, usize); 21] {
|
||||
[
|
||||
("sets", self.sets.len()),
|
||||
("materials", self.materials.len()),
|
||||
@@ -564,6 +573,7 @@ impl Model {
|
||||
("face_merges", self.face_merges.len()),
|
||||
("stitches", self.stitches.len()),
|
||||
("face_splits", self.face_splits.len()),
|
||||
("defeatures", self.defeatures.len()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,3 +237,56 @@ mod tests {
|
||||
assert_eq!(m.face_merges().len(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Most defeatures a model holds.
|
||||
pub const MAX_DEFEATURES: usize = 1024;
|
||||
/// Most features one defeature names.
|
||||
pub const MAX_DEFEATURE_FEATURES: usize = 1024;
|
||||
|
||||
/// Features of the design's timeline taken out for meshing (`geometry.defeature`): holes filled,
|
||||
/// fillets and chamfers back to their sharp edges, bosses removed, by feature id (`F<id>` in
|
||||
/// persistent names).
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Defeature {
|
||||
pub name: String,
|
||||
pub features: Vec<u64>,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
/// The defeatures, in the order they were made.
|
||||
pub fn defeatures(&self) -> &[Defeature] {
|
||||
&self.defeatures
|
||||
}
|
||||
|
||||
/// Add a defeature, or replace the features of the one of that name (in its place).
|
||||
pub fn set_defeature(&mut self, defeature: Defeature) -> Result<()> {
|
||||
let name = defeature.name.clone();
|
||||
check_name("defeature", &name)?;
|
||||
let invalid = |m: String| context("defeature", &name, Error::Invalid(m));
|
||||
if defeature.features.is_empty() || defeature.features.len() > MAX_DEFEATURE_FEATURES {
|
||||
return Err(invalid(format!("1 to {MAX_DEFEATURE_FEATURES} features")));
|
||||
}
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
if let Some(id) = defeature.features.iter().find(|id| !seen.insert(**id)) {
|
||||
return Err(invalid(format!("feature F{id} is listed twice")));
|
||||
}
|
||||
match self.defeatures.iter().position(|d| d.name == name) {
|
||||
Some(i) => {
|
||||
if let Some(d) = self.defeatures.get_mut(i) {
|
||||
*d = defeature;
|
||||
}
|
||||
}
|
||||
None if self.defeatures.len() >= MAX_DEFEATURES => {
|
||||
return Err(Error::Limit(format!("a model holds at most {MAX_DEFEATURES} defeatures")));
|
||||
}
|
||||
None => self.defeatures.push(defeature),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_defeature(&mut self, name: &str) -> Result<Defeature> {
|
||||
let i = self.defeatures.iter().position(|d| d.name == name).ok_or_else(|| Error::NotFound(format!("defeature `{name}`")))?;
|
||||
Ok(self.defeatures.remove(i))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user