Sweep history records in the reference layout; kernel and codec revs

New sweep records store the source and placed profile frames, the
default mitred joint, groups 292-294 and a 3D polyline path as a wire
body, so the reference re-evaluates them. Builds against the sweep
history codec and kernel revisions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-06 15:33:47 +03:00
1 parent 2dfa9f3f2a
commit 632540efff
6 files changed
+61 -13

No files matched your search

Generated
+2 -2
View File
@@ -4205,7 +4205,7 @@ dependencies = [
[[package]]
name = "opencadcodec"
version = "0.6.0"
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=1ca7d33#1ca7d3360a34384b59297ffe8aa18b157d2701d9"
source = "git+https://github.com/ramox81/cadcodec.git?rev=08b2296#08b229649d5afc5ed948726088df15d72f404c29"
dependencies = [
"anyhow",
"bitflags 2.13.1",
@@ -4237,7 +4237,7 @@ dependencies = [
[[package]]
name = "opencadkernel"
version = "0.1.0"
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=7fb0abb#7fb0abb4ee8e4266a770eb673ac7757c71321513"
source = "git+https://github.com/ramox81/cadkernel.git?rev=a259e57#a259e570fc727fca273ac0b266616045744ad408"
dependencies = [
"cavalier_contours",
"opencadcodec",
+6
View File
@@ -94,6 +94,12 @@ objc2-foundation = { version = "0.2", features = ["NSArray", "NSURL", "NSString"
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
[patch."https://github.com/HakanSeven12/opencadcodec.git"]
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "08b2296" }
[patch."https://github.com/HakanSeven12/opencadkernel.git"]
opencadkernel = { git = "https://github.com/ramox81/cadkernel.git", rev = "a259e57" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
getrandom = "0.3"
ocs_plugin_api = { path = "crates/ocs_plugin_api", features = ["host"] }
+4 -1
View File
@@ -486,6 +486,8 @@ impl OpenCADStudio {
.iter()
.map(|(_, entity)| entity.clone())
.collect::<Vec<_>>();
// Group 294: a base point the user picked.
let picked_base = options.base_point.is_some();
let options = sweep_model::sweep_selection_options(&selection, options);
let pending = if profiles.is_empty() {
None
@@ -496,7 +498,8 @@ impl OpenCADStudio {
let mut consumed = Vec::new();
for (handle, profile) in profiles {
let result = path.as_ref().zip(options).and_then(|(path, options)| {
let record = sweep_model::sweep_record(&profile, path, options)?;
let mut record = sweep_model::sweep_record(&profile, path, options)?;
record.flags_294_296[0] |= picked_base;
let (_, _, closed) = kernel::acis::sweep_profile_geometry(
record.sweep_entity.as_ref()?,
record.sweep_entity_transform,
+3 -3
View File
@@ -315,7 +315,7 @@ fn history_operation_text(operation: &SolidHistoryOperation) -> String {
value.base_face
),
SolidHistoryOperation::Sweep(value) | SolidHistoryOperation::Extrusion(value) => format!(
"{}; sweep {}; path {}; direction {:.6},{:.6},{:.6}; draft {:.6}; scale {:.6}; twist {:.6}; align {:.6}; bank {}; intersections {}",
"{}; sweep {}; path {}; direction {:.6},{:.6},{:.6}; draft {:.6}; scale {:.6}; twist {:.6}; align {:.6}; align start {}; bank {}",
history_base_text(&value.base),
embedded_name(value.sweep_entity.as_ref()),
embedded_name(value.path_entity.as_ref()),
@@ -326,8 +326,8 @@ fn history_operation_text(operation: &SolidHistoryOperation) -> String {
value.scale_factor,
value.twist_angle,
value.align_angle,
value.bank,
value.check_intersections
value.align_start,
value.bank
),
SolidHistoryOperation::Loft(value) => format!(
"{}; cross sections {}; guides {}",
+1 -1
View File
@@ -651,7 +651,7 @@ pub fn extrusion_surface_data(
path_entity_transform: value.path_entity_transform,
is_solid: false,
sweep_alignment_flags: value.align_option as i16,
align_start: value.has_align_start,
align_start: value.align_start,
bank: value.bank,
base_point_set: true,
reference_vector: value.reference_point,
+45 -6
View File
@@ -17,6 +17,24 @@ fn embedded_sweep_profile(entity: &EntityType) -> Option<(codec::entities::Embed
}
}
/// The sweep path as the reference records it: a 3D polyline as a wire
/// body, anything else as its embedded entity.
fn embedded_sweep_path(path: &EntityType) -> Option<codec::entities::EmbeddedEntity> {
let EntityType::Polyline3D(value) = path else {
return embedded_path(path);
};
let points = value.vertices.iter()
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z])
.collect::<Vec<_>>();
let mut document = codec::entities::acis::SatDocument::new();
kernel::acis::append_polyline_wire(&points, value.is_closed(), &mut document).ok()?;
Some(codec::entities::EmbeddedEntity::Body {
// The 3D polyline object type.
type_code: 16,
acis_data: codec::entities::AcisData::from_sat(&document.to_sat_string()),
})
}
pub fn is_sweep_profile(entity: &EntityType) -> bool {
embedded_sweep_profile(entity).is_some_and(|(profile, transform)| {
kernel::acis::sweep_profile_geometry(&profile, transform).is_ok()
@@ -64,10 +82,11 @@ pub fn sweep_record(profile: &EntityType, path: &EntityType, options: SweepOptio
base,
operation_major: 1,
sweep_entity: Some(sweep_entity),
path_entity: Some(embedded_path(path)?),
path_entity: Some(embedded_sweep_path(path)?),
scale_factor: options.scale,
twist_angle: options.twist_angle,
align_option: u8::from(options.align),
// 1 aligns the profile to the path; 2 only moves it to the path start.
align_option: if options.align { 1 } else { 2 },
has_align_start: true,
bank: options.bank,
sweep_entity_transform,
@@ -100,12 +119,32 @@ fn placed_sweep_record(profile: &EntityType, mut record: SolidHistorySweep) -> O
[0.0, 0.0, 0.0, 1.0],
],
});
// The record's matrices are the source profile frame (at the base point,
// in the profile plane) and the frame it is placed in at the path start;
// the reference re-places the profile from them when it re-evaluates.
let (plane, _, _) = kernel::acis::sweep_profile_geometry(
record.sweep_entity.as_ref()?,
record.sweep_entity_transform,
).ok()?;
let x_axis = glam::DVec3::from_array(plane.x_axis).try_normalize()?;
let normal = glam::DVec3::from_array(plane.normal()?);
let base = glam::DVec3::new(record.reference_point.x, record.reference_point.y, record.reference_point.z);
let source_frame = glam::DMat4::from_cols(
x_axis.extend(0.0),
normal.cross(x_axis).extend(0.0),
normal.extend(0.0),
base.extend(1.0),
);
let mut moved = profile.clone();
crate::scene::view::dispatch::apply_transform(&mut moved, &crate::command::EntityTransform::Affine(transform));
let (sweep_entity, sweep_entity_transform) = embedded_sweep_profile(&moved)?;
let (sweep_entity, _) = embedded_sweep_profile(&moved)?;
record.sweep_entity = Some(sweep_entity);
record.sweep_entity_transform = sweep_entity_transform;
record.flags_294_296 = [false, true, true];
record.sweep_entity_transform = source_frame.to_cols_array();
record.path_entity_transform = (map * source_frame).to_cols_array();
// Group 294 marks a profile only moved to the path, not turned onto it.
record.flags_294_296 = [record.align_option != 1, true, true];
// The reference records its default mitred joint.
record.miter_option = 2;
record.reference_point = Vector3::new(0.0, 0.0, 0.0);
Some(record)
}
@@ -135,7 +174,7 @@ pub fn swept_surface_entity(record: &SolidHistorySweep) -> EntityType {
sweep_entity_transform: record.sweep_entity_transform,
path_entity_transform: record.path_entity_transform,
sweep_alignment_flags: record.align_option as i16,
align_start: record.has_align_start,
align_start: record.align_start,
bank: record.bank,
base_point_set: true,
reference_vector: record.reference_point,