forked from 1b-agent/opencadstudio-upstream
Merge PR #1589 from ramox81/codex/history-frame-lift: centre-framed boxes and wedges; no double transform after ACIS lift
The PR pinned codec and kernel to its fork through [patch]; codec #77 and kernel #73 are merged upstream, so the patch sections are replaced by the upstream pins (codec 8d23408, kernel d22a270, graph 9b5ae39) in this same commit: the kernel now applies the body transform during the lift, and an OCS without this PR's change would apply it twice. The new codec also brings AssocCurveValue, registered with the plugin API's type registry, and EmbeddedEntity::Body, named as a polyline profile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
54a4a02d62
12 files changed
+83
-45
No files matched your search
Generated
+4
-4
@@ -4206,7 +4206,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadcodec"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=d96e3fa#d96e3fa2fe5acbeac966f1db4c01142618bf9c79"
|
||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=8d23408#8d2340876caef34f68436f62e2c9402be0aabb28"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
@@ -4229,7 +4229,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadgraph"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=10d0858#10d0858a7252f85df07be4dfa00946658b6979e6"
|
||||
source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=9b5ae39#9b5ae39ea35567e67faf8bc8d20b40e2bbab1177"
|
||||
dependencies = [
|
||||
"opencadkernel",
|
||||
"serde_json",
|
||||
@@ -4238,7 +4238,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadkernel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=9cdd36d#9cdd36dc527216ba7929d8cfcdc1b7712a2d4cb8"
|
||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=d22a270#d22a270a0af79db9f10428a2d941152f6bb28158"
|
||||
dependencies = [
|
||||
"cavalier_contours",
|
||||
"opencadcodec",
|
||||
@@ -4249,7 +4249,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadkernel-constraints"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=9cdd36d#9cdd36dc527216ba7929d8cfcdc1b7712a2d4cb8"
|
||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=d22a270#d22a270a0af79db9f10428a2d941152f6bb28158"
|
||||
dependencies = [
|
||||
"nalgebra",
|
||||
]
|
||||
|
||||
+4
-4
@@ -34,10 +34,10 @@ rfd = "0.17"
|
||||
clap = { version = "4", features = ["derive", "string"] }
|
||||
env_logger = "0.11"
|
||||
log = "0.4"
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d96e3fa", features = ["serde"] }
|
||||
kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "9cdd36d", features = ["acis", "offset"] }
|
||||
kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "9cdd36d" }
|
||||
graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "10d0858" }
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "8d23408", features = ["serde"] }
|
||||
kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "d22a270", features = ["acis", "offset"] }
|
||||
kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "d22a270" }
|
||||
graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "9b5ae39" }
|
||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||
flate2 = "1"
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||
|
||||
@@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true }
|
||||
# Pulled in only by the `host` feature, which adds the `opencadcodec`-typed
|
||||
# `HostApi` runtime surface. The default crate stays dependency-free so engine
|
||||
# crates and external tooling can depend on the manifest/ribbon contract cheaply.
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d96e3fa", optional = true, features = ["serde"] }
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "8d23408", optional = true, features = ["serde"] }
|
||||
|
||||
# Runtime IPC and serialization (host feature only).
|
||||
interprocess = { version = "2", optional = true }
|
||||
@@ -39,7 +39,7 @@ serde_json = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
cargo-lock = "11"
|
||||
# opencadcodec is scanned at build time to generate the embedded type registry.
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d96e3fa", features = ["serde"] }
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "8d23408", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
@@ -162,6 +162,10 @@ fn generate_type_registry(out_dir: &Path) {
|
||||
"AssocConstraintNodeData",
|
||||
trace_simple::<codec::objects::AssocConstraintNodeData>,
|
||||
),
|
||||
(
|
||||
"AssocCurveValue",
|
||||
trace_simple::<codec::objects::AssocCurveValue>,
|
||||
),
|
||||
(
|
||||
"AssocEvalValue",
|
||||
trace_simple::<codec::objects::AssocEvalValue>,
|
||||
|
||||
@@ -8,7 +8,7 @@ publish = false
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d96e3fa", features = ["serde"] }
|
||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "8d23408", features = ["serde"] }
|
||||
bincode = "1.3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
|
||||
Generated
+1
-1
@@ -1265,7 +1265,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadcodec"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=d96e3fa#d96e3fa2fe5acbeac966f1db4c01142618bf9c79"
|
||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=8d23408#8d2340876caef34f68436f62e2c9402be0aabb28"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
|
||||
@@ -228,6 +228,8 @@ fn embedded_name(value: Option<&codec::entities::EmbeddedEntity>) -> &'static st
|
||||
Some(codec::entities::EmbeddedEntity::Ellipse(_)) => "Ellipse",
|
||||
Some(codec::entities::EmbeddedEntity::Spline(_)) => "Spline",
|
||||
Some(codec::entities::EmbeddedEntity::LwPolyline(_)) => "Polyline",
|
||||
// A 2D / 3D polyline profile the modeler keeps as a wire body.
|
||||
Some(codec::entities::EmbeddedEntity::Body { .. }) => "Polyline",
|
||||
Some(codec::entities::EmbeddedEntity::Region(_)) => "Region",
|
||||
Some(codec::entities::EmbeddedEntity::Ray(_)) => "Ray",
|
||||
Some(codec::entities::EmbeddedEntity::XLine(_)) => "XLine",
|
||||
|
||||
@@ -447,6 +447,8 @@ fn embedded_name(entity: Option<&codec::entities::EmbeddedEntity>) -> &'static s
|
||||
Some(codec::entities::EmbeddedEntity::Ellipse(_)) => "Ellipse",
|
||||
Some(codec::entities::EmbeddedEntity::Spline(_)) => "Spline",
|
||||
Some(codec::entities::EmbeddedEntity::LwPolyline(_)) => "Polyline",
|
||||
// A 2D / 3D polyline profile the modeler keeps as a wire body.
|
||||
Some(codec::entities::EmbeddedEntity::Body { .. }) => "Polyline",
|
||||
Some(codec::entities::EmbeddedEntity::Region(_)) => "Region",
|
||||
Some(codec::entities::EmbeddedEntity::Ray(_)) => "Ray",
|
||||
Some(codec::entities::EmbeddedEntity::XLine(_)) => "XLine",
|
||||
|
||||
@@ -1894,7 +1894,7 @@ impl PrimitiveCommand {
|
||||
Some((
|
||||
placed,
|
||||
solid_history::box_op(
|
||||
self.history_transform_axes(origin, x_axis, y_axis),
|
||||
self.history_transform_axes(box_centre(origin, x_axis, y_axis, length, width, height), x_axis, y_axis),
|
||||
length,
|
||||
width,
|
||||
height,
|
||||
@@ -2024,7 +2024,7 @@ impl PrimitiveCommand {
|
||||
Some((
|
||||
placed,
|
||||
solid_history::wedge_op(
|
||||
self.history_transform_axes(origin, x_axis, y_axis),
|
||||
self.history_transform_axes(box_centre(origin, x_axis, y_axis, length, width, height), x_axis, y_axis),
|
||||
length,
|
||||
width,
|
||||
height,
|
||||
@@ -3714,3 +3714,9 @@ fn wire(name: &str, points: Vec<[f32; 3]>) -> WireModel {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Box and wedge histories are framed at the centre of their bounding box,
|
||||
/// as the reference stores them (lengths stay positive).
|
||||
fn box_centre(origin: DVec3, x_axis: DVec3, y_axis: DVec3, length: f64, width: f64, height: f64) -> DVec3 {
|
||||
origin + x_axis * (length * 0.5) + y_axis * (width * 0.5) + DVec3::Z * (height * 0.5)
|
||||
}
|
||||
@@ -31,23 +31,14 @@ pub fn tessellate_sat(
|
||||
if bodies.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// The kernel's lift already applies each body's transform record; its
|
||||
// scale still sets the tessellation tolerance.
|
||||
let mut placed_bodies = Vec::with_capacity(bodies.len());
|
||||
for body in bodies {
|
||||
let source = body.provenance.source()?;
|
||||
let transform = body_transform(document, source.index() as usize).ok()?;
|
||||
let placement_scale = transform.map_or(1.0, |(_, _, scale)| scale.abs());
|
||||
let placed = if let Some((matrix, translation, scale)) = transform {
|
||||
let placement = brep::Placement {
|
||||
x_axis: [scale * matrix[0], scale * matrix[1], scale * matrix[2]],
|
||||
y_axis: [scale * matrix[3], scale * matrix[4], scale * matrix[5]],
|
||||
z_axis: [scale * matrix[6], scale * matrix[7], scale * matrix[8]],
|
||||
origin: translation,
|
||||
};
|
||||
brep::transform(&body, &placement)?
|
||||
} else {
|
||||
body
|
||||
};
|
||||
placed_bodies.push((placed, placement_scale));
|
||||
placed_bodies.push((body, placement_scale));
|
||||
}
|
||||
let bodies = placed_bodies;
|
||||
let resolution = if facet_res.is_finite() && facet_res > 0.0 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use codec::entities::acis::{SabReader, SatBody, SatDocument};
|
||||
use codec::entities::{Body, Region, Solid3D, Surface};
|
||||
use kernel::brep::{self, Body as KernelBody};
|
||||
use kernel::brep::Body as KernelBody;
|
||||
|
||||
use crate::scene::model::mesh_model::{MeshLodSet, MeshModel};
|
||||
|
||||
@@ -179,21 +179,8 @@ pub(crate) fn kernel_acis_body(acis: &codec::entities::AcisData) -> Option<Kerne
|
||||
if !loss.is_empty() || bodies.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
let body = bodies.pop()?;
|
||||
let source = body.provenance.source()?;
|
||||
let Some((matrix, translation, scale)) = body_transform(&sat, source.index() as usize).ok()?
|
||||
else {
|
||||
return Some(body);
|
||||
};
|
||||
brep::transform(
|
||||
&body,
|
||||
&brep::Placement {
|
||||
x_axis: [scale * matrix[0], scale * matrix[1], scale * matrix[2]],
|
||||
y_axis: [scale * matrix[3], scale * matrix[4], scale * matrix[5]],
|
||||
z_axis: [scale * matrix[6], scale * matrix[7], scale * matrix[8]],
|
||||
origin: translation,
|
||||
},
|
||||
)
|
||||
// The kernel's lift already applies the body's transform record.
|
||||
bodies.pop()
|
||||
}
|
||||
|
||||
fn remap_acis_material_bindings(
|
||||
|
||||
@@ -278,7 +278,7 @@ pub fn reference_point(operation: &SolidHistoryOperation) -> Option<glam::DVec3>
|
||||
match operation {
|
||||
SolidHistoryOperation::Box(value) | SolidHistoryOperation::Wedge(value) => world_point(
|
||||
value.base.transform,
|
||||
[value.length * 0.5, value.width * 0.5, 0.0],
|
||||
[0.0, 0.0, -value.height * 0.5],
|
||||
),
|
||||
SolidHistoryOperation::Sphere(value) => {
|
||||
world_point(value.base.transform, [0.0, 0.0, 0.0])
|
||||
@@ -1615,9 +1615,10 @@ pub fn primitive_properties(
|
||||
) {
|
||||
return Vec::new();
|
||||
}
|
||||
let Some(operation) = primitive_property_operation(document, handle) else {
|
||||
let Some(mut operation) = primitive_property_operation(document, handle) else {
|
||||
return brep_properties(document, handle);
|
||||
};
|
||||
corner_frame(&mut operation);
|
||||
match &operation {
|
||||
SolidHistoryOperation::Box(value) => {
|
||||
rectangular_properties(document, handle, value, "Box")
|
||||
@@ -2414,6 +2415,17 @@ pub fn apply_primitive_property(
|
||||
operation: &mut SolidHistoryOperation,
|
||||
field: &str,
|
||||
value: &str,
|
||||
) -> bool {
|
||||
corner_frame(operation);
|
||||
let applied = apply_primitive_property_at_corner(operation, field, value);
|
||||
centre_frame(operation);
|
||||
applied
|
||||
}
|
||||
|
||||
fn apply_primitive_property_at_corner(
|
||||
operation: &mut SolidHistoryOperation,
|
||||
field: &str,
|
||||
value: &str,
|
||||
) -> bool {
|
||||
if let SolidHistoryOperation::Brep(brep_value) = operation {
|
||||
if let Some(applied) = apply_brep_position_property(brep_value, field, value) {
|
||||
@@ -2757,7 +2769,7 @@ fn embedded_entity(value: &EmbeddedEntity) -> Option<EntityType> {
|
||||
EmbeddedEntity::Region(value) => EntityType::Region(value.clone()),
|
||||
EmbeddedEntity::Ray(value) => EntityType::Ray(value.clone()),
|
||||
EmbeddedEntity::XLine(value) => EntityType::XLine(value.clone()),
|
||||
EmbeddedEntity::Unknown { .. } => return None,
|
||||
EmbeddedEntity::Body { .. } | EmbeddedEntity::Unknown { .. } => return None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3460,6 +3472,9 @@ pub fn primitive_grips(
|
||||
let Some(operation) = document.solid_history_operation(handle) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut operation = operation.clone();
|
||||
corner_frame(&mut operation);
|
||||
let operation = &operation;
|
||||
if let SolidHistoryOperation::Fillet(value) = operation {
|
||||
let Some(radius) = value.radii.first().copied() else {
|
||||
return Vec::new();
|
||||
@@ -3743,6 +3758,17 @@ pub fn apply_primitive_grip(
|
||||
operation: &mut SolidHistoryOperation,
|
||||
grip_id: usize,
|
||||
apply: GripApply,
|
||||
) -> bool {
|
||||
corner_frame(operation);
|
||||
let applied = apply_primitive_grip_at_corner(operation, grip_id, apply);
|
||||
centre_frame(operation);
|
||||
applied
|
||||
}
|
||||
|
||||
fn apply_primitive_grip_at_corner(
|
||||
operation: &mut SolidHistoryOperation,
|
||||
grip_id: usize,
|
||||
apply: GripApply,
|
||||
) -> bool {
|
||||
if let SolidHistoryOperation::Revolve(value) = operation {
|
||||
if let Some(index) = grip_id.checked_sub(GRIP_REVOLVE_PROFILE_FIRST) {
|
||||
@@ -4138,3 +4164,23 @@ pub fn chamfer_op(
|
||||
..SolidHistoryChamfer::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Box and wedge histories are framed at the centre of their bounding box,
|
||||
/// as the reference stores them; the editing code here works in the frame at
|
||||
/// the base corner. These move a box or wedge between the two frames.
|
||||
fn corner_frame(operation: &mut SolidHistoryOperation) {
|
||||
shift_rectangular_frame(operation, -0.5);
|
||||
}
|
||||
|
||||
fn centre_frame(operation: &mut SolidHistoryOperation) {
|
||||
shift_rectangular_frame(operation, 0.5);
|
||||
}
|
||||
|
||||
fn shift_rectangular_frame(operation: &mut SolidHistoryOperation, factor: f64) {
|
||||
if let SolidHistoryOperation::Box(value) | SolidHistoryOperation::Wedge(value) = operation {
|
||||
if let Some(current) = matrix(value.base.transform) {
|
||||
let half = glam::DVec3::new(value.length, value.width, value.height) * factor;
|
||||
value.base.transform = (current * glam::DMat4::from_translation(half)).to_cols_array();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user