forked from 1b-agent/fieldcraft-upstream
Engine: the half crank extrudes in blocks through mesh.hex.generate and mesh.cells
The extrusion's automatic cross-section blocks reach both commands; the half crank arm, cut only on its symmetry plane, meshes all-structured (sJ >= 0.37) with no seeds either way, and mesh.hex.generate's description says so. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
02172f9a7e
commit
4c18322a34
2 files changed
+22
-1
No files matched your search
@@ -371,6 +371,27 @@ mod tests {
|
||||
assert_eq!(s.model.ties().len(), 1);
|
||||
}
|
||||
|
||||
/// The half crank arm (cut on its symmetry plane only) has no cell that maps or sweeps as
|
||||
/// the design gives it; the extrusion decomposes its cross-section into blocks itself, alike
|
||||
/// through mesh.hex.generate (auto) and mesh.cells, with no seeds.
|
||||
#[test]
|
||||
fn the_half_crank_extrudes_in_blocks_without_partitions() {
|
||||
let bytes = fieldcraft_geometry::script_design(crate::sample::CRANK_ARM).unwrap();
|
||||
let (_dir, path) = crate::tests::design_file(&bytes);
|
||||
let mut s = Session::default();
|
||||
s.execute("geometry.open", &json!({"path": path})).unwrap();
|
||||
s.execute("geometry.datum", &json!({"name": "Sym", "by": {"type": "offset", "plane": "zx", "offset": 0}})).unwrap();
|
||||
s.execute("geometry.partition", &json!({"name": "Half", "datum": "Sym"})).unwrap();
|
||||
let r = s.execute("mesh.hex.generate", &json!({"body": "CrankArm/a", "size": 3})).unwrap();
|
||||
let body = &r["bodies"][0];
|
||||
assert_eq!(body["method"], "extrude", "{r}");
|
||||
assert!(body["description"].as_str().unwrap().contains(" 0 free)"), "{r}");
|
||||
assert!(body["quality"]["min_scaled_jacobian"].as_f64().unwrap() >= 0.37, "{r}");
|
||||
let r = s.execute("mesh.cells", &json!({"bodies": ["CrankArm/a"], "default": "extrude", "size": 3})).unwrap();
|
||||
assert_eq!(r["cells"][0]["method"], "extrude", "{r}");
|
||||
assert_eq!(r["elements"], body["elements"], "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_falls_back_to_tet_and_says_why() {
|
||||
let (_dir, mut s) = cut_plate();
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::{CommandKind, CommandSpec, EngineError, Result, Session};
|
||||
pub const HEX_GENERATE: CommandSpec = CommandSpec {
|
||||
id: "mesh.hex.generate",
|
||||
label: "Hex Mesh",
|
||||
params: r#"{"body": "Body1" (default: every body of the open design) or "surface": 0 (an imported surface), "size": 2.0 (element size, mm; default 1/25 of the bounding-box diagonal), "order": 1 (hex8) or 2 (hex20, mid-edge nodes on the geometry), "method": "auto" (default) | "swept" (any sweep) | "extrude" | "sweep" | "revolve" | "mapped", "tolerance": 0.05 (chordal tolerance of the tessellation, mm; default 1e-3 of the diagonal)} — replaces the meshes of the bodies it meshes (as mesh.tet.generate; other bodies keep theirs) with structured hexahedra: multi-level sweeps along a direction or around an axis, one-to-one sweeps through linking faces, or mapped blocks. Boundary element faces are tagged with their B-rep faces (named as in geometry.bodies; by index when a face has no name; `weld`, `weld_distance` and `feature_angle` as in mesh.tet.generate), so sets by geometry resolve. Edge seeds (mesh.seed.edge) set the counts and spacing of their edges: exact seeds are held, and seeds that cannot all hold (opposite sides of a mapped face, the layers between two levels) are an error naming them. Reports per body the method, counts and quality; a body no structured method fits is an error that says why"#,
|
||||
params: r#"{"body": "Body1" (default: every body of the open design) or "surface": 0 (an imported surface), "size": 2.0 (element size, mm; default 1/25 of the bounding-box diagonal), "order": 1 (hex8) or 2 (hex20, mid-edge nodes on the geometry), "method": "auto" (default) | "swept" (any sweep) | "extrude" | "sweep" | "revolve" | "mapped", "tolerance": 0.05 (chordal tolerance of the tessellation, mm; default 1e-3 of the diagonal)} — replaces the meshes of the bodies it meshes (as mesh.tet.generate; other bodies keep theirs) with structured hexahedra: multi-level sweeps along a direction or around an axis (their cross-section cut into mappable blocks automatically: O-grids round holes, triangle primitives, four-sided blocks; nothing is added to the model), one-to-one sweeps through linking faces, or mapped blocks. Boundary element faces are tagged with their B-rep faces (named as in geometry.bodies; by index when a face has no name; `weld`, `weld_distance` and `feature_angle` as in mesh.tet.generate), so sets by geometry resolve. Edge seeds (mesh.seed.edge) set the counts and spacing of their edges: exact seeds are held, and seeds that cannot all hold (opposite sides of a mapped face, the layers between two levels) are an error naming them. Reports per body the method, counts and quality; a body no structured method fits is an error that says why"#,
|
||||
form: Some(super::forms::HEX_GENERATE),
|
||||
kind: CommandKind::Model,
|
||||
requires: &[Requirement::Geometry],
|
||||
|
||||
Reference in new issue
Block a user