forked from 1b-agent/opencadstudio-upstream
chore: bump codec d28fd71, kernel a03e4f0, graph 79bdc4b
Codec: PRs #71-#74 merged (MPOLYGON layout, multiline ATTDEF/ATTRIB DXF, DXF MATERIAL/ACSH matrix, restorable SAT/SAB + history roots) and issues #55 #64-#69 fixed. EntityType now boxes Surface, Extended, Table, MultiLeader and Helix (2344 B -> 848 B per entity): construction sites wrap in Box, the entity traits forward through Box, and the python plugin generator converts with into(). Kernel: PR #70 (cuboid ring winding). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8c1471078d
commit
443b935a3f
31 files changed
+147
-84
No files matched your search
@@ -965,16 +965,16 @@ mod thicken_tests {
|
||||
)
|
||||
.unwrap();
|
||||
let source = app.add_surface_model(
|
||||
codec::EntityType::Surface(Surface::new(SurfaceKind::Plane)),
|
||||
codec::EntityType::Surface(Box::new(Surface::new(SurfaceKind::Plane))),
|
||||
body,
|
||||
);
|
||||
assert!(!source.is_null());
|
||||
let i = app.active_tab;
|
||||
let invalid = app.tabs[i]
|
||||
.scene
|
||||
.add_entity(codec::EntityType::Surface(Surface::new(
|
||||
.add_entity(codec::EntityType::Surface(Box::new(Surface::new(
|
||||
SurfaceKind::Generic,
|
||||
)));
|
||||
))));
|
||||
let original =
|
||||
serde_json::to_value(app.tabs[i].scene.document.get_entity(source).unwrap()).unwrap();
|
||||
let before = app.tabs[i].history.undo_stack.len();
|
||||
@@ -1060,7 +1060,7 @@ mod thicken_tests {
|
||||
kernel::brep::extrude_surface(Plane::XY, &[Curve::Nurbs(profile)], [0.0, 0.0, 2.0])
|
||||
.unwrap();
|
||||
let source = app.add_surface_model(
|
||||
codec::EntityType::Surface(Surface::new(SurfaceKind::Generic)),
|
||||
codec::EntityType::Surface(Box::new(Surface::new(SurfaceKind::Generic))),
|
||||
body,
|
||||
);
|
||||
let i = app.active_tab;
|
||||
|
||||
@@ -322,7 +322,7 @@ impl OpenCADStudio {
|
||||
"_PCCROPCIRC" => "C",
|
||||
_ => "",
|
||||
};
|
||||
let command = crate::modules::insert::pc_crop::PointCloudCropCommand::for_cloud(handle, cloud, option);
|
||||
let command = crate::modules::insert::pc_crop::PointCloudCropCommand::for_cloud(handle, *cloud, option);
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
}
|
||||
|
||||
@@ -163,10 +163,10 @@ impl OpenCADStudio {
|
||||
elevation_as_gradient: false,
|
||||
croppings: Vec::new(),
|
||||
};
|
||||
let entity = codec::EntityType::Extended(codec::entities::ExtendedEntity {
|
||||
let entity = codec::EntityType::Extended(Box::new(codec::entities::ExtendedEntity {
|
||||
common: codec::entities::EntityCommon::new(),
|
||||
data: codec::entities::ExtendedEntityData::PointCloudEx(data),
|
||||
});
|
||||
}));
|
||||
if let Some(cloud) = self.commit_entity_handle(entity) {
|
||||
// The reactor, owned by the cloud, tells the definition who uses it.
|
||||
let document = &mut self.tabs[i].scene.document;
|
||||
|
||||
+9
-9
@@ -685,15 +685,15 @@ impl OpenCADStudio {
|
||||
/// Add is delta-safe when its layer and XData application IDs already exist
|
||||
/// and it creates no block records.
|
||||
pub(super) fn delta_add_safe(&self, i: usize, entity: &EntityType) -> bool {
|
||||
if matches!(
|
||||
entity,
|
||||
EntityType::Block(_)
|
||||
| EntityType::BlockEnd(_)
|
||||
| EntityType::Extended(codec::entities::ExtendedEntity {
|
||||
data: codec::entities::ExtendedEntityData::SectionObject(_),
|
||||
..
|
||||
})
|
||||
) {
|
||||
if matches!(entity, EntityType::Block(_) | EntityType::BlockEnd(_))
|
||||
|| matches!(
|
||||
entity,
|
||||
EntityType::Extended(extended) if matches!(
|
||||
extended.data,
|
||||
codec::entities::ExtendedEntityData::SectionObject(_)
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let layer = entity.common().layer.clone();
|
||||
|
||||
@@ -1354,7 +1354,7 @@ impl super::OpenCADStudio {
|
||||
let mut entity = Surface::new(SurfaceKind::Generic);
|
||||
entity.common = group.common;
|
||||
self.add_surface_model_preserving_style(
|
||||
EntityType::Surface(entity),
|
||||
EntityType::Surface(Box::new(entity)),
|
||||
group.body,
|
||||
)
|
||||
}
|
||||
@@ -2316,7 +2316,7 @@ impl super::OpenCADStudio {
|
||||
}
|
||||
let n = surfaces.len();
|
||||
for surf in surfaces {
|
||||
self.tabs[i].scene.add_entity(EntityType::Surface(surf));
|
||||
self.tabs[i].scene.add_entity(EntityType::Surface(Box::new(surf)));
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_properties();
|
||||
|
||||
@@ -198,14 +198,14 @@ impl<'a> HostSession<'a> {
|
||||
}
|
||||
if let EntityType::Helix(new) = entity {
|
||||
let old = match old {
|
||||
Some(EntityType::Helix(old)) => Some(old),
|
||||
Some(EntityType::Helix(old)) => Some(&**old),
|
||||
_ => None,
|
||||
};
|
||||
crate::entities::helix::normalize_scripted_helix(old, new)?;
|
||||
}
|
||||
if let EntityType::Table(new) = entity {
|
||||
let old = match old {
|
||||
Some(EntityType::Table(old)) => Some(old),
|
||||
Some(EntityType::Table(old)) => Some(&**old),
|
||||
_ => None,
|
||||
};
|
||||
crate::entities::table::normalize_scripted_table(old, new);
|
||||
@@ -758,7 +758,7 @@ impl<'a> HostSession<'a> {
|
||||
surface.wires = model::edge_wires(&body);
|
||||
surface.acis_data = codec::entities::AcisData::from_sat(&sat.to_sat_string());
|
||||
surface.common.layer = layer;
|
||||
self.commit_profile_result(EntityType::Surface(surface), source, delete_source, "Create surface")
|
||||
self.commit_profile_result(EntityType::Surface(Box::new(surface)), source, delete_source, "Create surface")
|
||||
}
|
||||
SolidOperation::Extrude { source, direction, layer, delete_source } => {
|
||||
if direction.iter().any(|v| !v.is_finite()) {
|
||||
@@ -788,7 +788,7 @@ impl<'a> HostSession<'a> {
|
||||
surface.wires = model::edge_wires(&body);
|
||||
surface.acis_data = codec::entities::AcisData::from_sat(&sat.to_sat_string());
|
||||
surface.common.layer = layer;
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
};
|
||||
self.commit_profile_result(result, source, delete_source, "Extrude profile")
|
||||
}
|
||||
@@ -7201,7 +7201,7 @@ mod tests {
|
||||
let unliftable = host.add_entity(EntityType::Solid3D(codec::entities::Solid3D::new()));
|
||||
let mut plane = codec::entities::Surface::new(codec::entities::SurfaceKind::Plane);
|
||||
plane.acis_data = codec::entities::AcisData::new();
|
||||
let surface = host.add_entity(EntityType::Surface(plane));
|
||||
let surface = host.add_entity(EntityType::Surface(Box::new(plane)));
|
||||
let far = { dispatch(&mut host, "PY_EVAL ocs.active_document.solids.box(center=(500, 500, 500), size=(1, 1, 1)).handle");
|
||||
*solids_in(host.document()).last().unwrap() };
|
||||
let counts = (host.document().entities().count(), host.app.tabs[0].history.undo_stack.len());
|
||||
|
||||
@@ -140,7 +140,7 @@ impl super::OpenCADStudio {
|
||||
surface.surface_data = solid_history::extrusion_surface_data(record)
|
||||
.ok_or("PRESSPULL: the surface parameters could not be retained.")?;
|
||||
}
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
};
|
||||
(body, history, entity)
|
||||
}
|
||||
|
||||
@@ -10922,7 +10922,7 @@ mod free_text_entry_tests {
|
||||
let handle = app.tabs[0]
|
||||
.scene
|
||||
.document
|
||||
.add_entity(EntityType::Table(table.clone()))
|
||||
.add_entity(EntityType::Table(Box::new(table.clone())))
|
||||
.unwrap();
|
||||
app.set_active_command(0, Box::new(TableCellEditCommand::new(handle, &table, 0, 0)));
|
||||
(app, handle)
|
||||
|
||||
@@ -2108,7 +2108,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
|
||||
let host = codec::EntityType::MultiLeader(ml.clone());
|
||||
let host = codec::EntityType::MultiLeader(Box::new(ml.clone()));
|
||||
for block_use in crate::scene::render_graph::entity_render_block_uses(document, &host, 1.0)
|
||||
.into_iter()
|
||||
.filter(|block_use| {
|
||||
|
||||
@@ -81,6 +81,63 @@ pub trait Transformable {
|
||||
fn apply_transform(&mut self, t: &EntityTransform);
|
||||
}
|
||||
|
||||
// The codec boxes its rare wide entity kinds (Surface, Table, MultiLeader,
|
||||
// Helix, Extended) so every other entity is stored narrow; the boxed ones
|
||||
// answer through their contents.
|
||||
impl<T: RenderConvertible + ?Sized> RenderConvertible for Box<T> {
|
||||
fn to_render(&self, document: &CadDocument) -> Option<RenderEntity> {
|
||||
(**self).to_render(document)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Grippable + ?Sized> Grippable for Box<T> {
|
||||
fn grips(&self) -> Vec<GripDef> {
|
||||
(**self).grips()
|
||||
}
|
||||
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
|
||||
(**self).apply_grip(grip_id, apply)
|
||||
}
|
||||
fn grip_menu(&self, grip_id: usize) -> Vec<GripMenuItem> {
|
||||
(**self).grip_menu(grip_id)
|
||||
}
|
||||
fn apply_grip_menu(&mut self, grip_id: usize, action: GripMenuAction) {
|
||||
(**self).apply_grip_menu(grip_id, action)
|
||||
}
|
||||
fn apply_grip_menu_value(&mut self, grip_id: usize, action: GripMenuAction, value: f64) {
|
||||
(**self).apply_grip_menu_value(grip_id, action, value)
|
||||
}
|
||||
fn grip_menu_value_prompt(
|
||||
&self,
|
||||
grip_id: usize,
|
||||
action: GripMenuAction,
|
||||
) -> Option<&'static str> {
|
||||
(**self).grip_menu_value_prompt(grip_id, action)
|
||||
}
|
||||
fn grip_menu_point_value(
|
||||
&self,
|
||||
grip_id: usize,
|
||||
action: GripMenuAction,
|
||||
point: glam::DVec3,
|
||||
) -> Option<f64> {
|
||||
(**self).grip_menu_point_value(grip_id, action, point)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PropertyEditable + ?Sized> PropertyEditable for Box<T> {
|
||||
fn geometry_properties(&self, text_style_names: &[String]) -> Vec<PropSection> {
|
||||
(**self).geometry_properties(text_style_names)
|
||||
}
|
||||
fn apply_geom_prop(&mut self, field: &str, value: &str) {
|
||||
(**self).apply_geom_prop(field, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transformable + ?Sized> Transformable for Box<T> {
|
||||
fn apply_transform(&mut self, t: &EntityTransform) {
|
||||
(**self).apply_transform(t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inquiry-time mass / area / perimeter properties for entities whose
|
||||
/// 2D footprint has a meaningful area or perimeter (Circle, Arc, Line,
|
||||
/// LwPolyline, Ellipse). Entities outside this set get `None` via the
|
||||
|
||||
@@ -160,7 +160,7 @@ impl CadCommand for DataLinkPlaceCommand {
|
||||
self.table.insertion_point = codec::types::Vector3::new(point.x, point.y, point.z);
|
||||
CmdResult::CommitAndExit(
|
||||
self.plane
|
||||
.place_entity(EntityType::Table(self.table.clone())),
|
||||
.place_entity(EntityType::Table(Box::new(self.table.clone()))),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ impl MLeaderCommand {
|
||||
ml.text_style_handle = style_handle;
|
||||
ml.context.text_style_handle = style_handle;
|
||||
}
|
||||
let entity = self.plane.place_entity(EntityType::MultiLeader(ml));
|
||||
let entity = self.plane.place_entity(EntityType::MultiLeader(Box::new(ml)));
|
||||
if self.content_type == LeaderContentType::MText && self.text.is_empty() {
|
||||
CmdResult::CommitAndEditText(entity)
|
||||
} else {
|
||||
|
||||
@@ -271,7 +271,7 @@ impl TableCommand {
|
||||
row.style = Some(styles[row_index.min(2)].clone());
|
||||
}
|
||||
}
|
||||
self.plane.place_entity(EntityType::Table(table))
|
||||
self.plane.place_entity(EntityType::Table(Box::new(table)))
|
||||
}
|
||||
|
||||
fn preview_grid(
|
||||
@@ -795,7 +795,7 @@ impl CadCommand for TableCellEditCommand {
|
||||
cell.set_text(&formatted);
|
||||
self.table.block_record_handle = None;
|
||||
Some(CmdResult::ReplaceMany(
|
||||
vec![(self.handle, vec![EntityType::Table(self.table.clone())])],
|
||||
vec![(self.handle, vec![EntityType::Table(Box::new(self.table.clone()))])],
|
||||
Vec::new(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ impl HelixCommand {
|
||||
helix.turn_height = if curve.turns == 0.0 { 0.0 } else { height / curve.turns };
|
||||
helix.handedness = self.counter_clockwise;
|
||||
helix.constraint = self.constraint;
|
||||
Some(EntityType::Helix(helix))
|
||||
Some(EntityType::Helix(Box::new(helix)))
|
||||
}
|
||||
|
||||
fn commit(&mut self, height: f64, axis: DVec3) -> CmdResult {
|
||||
|
||||
@@ -75,7 +75,8 @@ impl ReverseCommand {
|
||||
}
|
||||
EntityType::Spline(sp) => Some(EntityType::Spline(reverse_spline(sp))),
|
||||
EntityType::Helix(helix) => {
|
||||
crate::entities::helix::reversed(helix).map(EntityType::Helix)
|
||||
crate::entities::helix::reversed(helix)
|
||||
.map(|helix| EntityType::Helix(Box::new(helix)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -117,7 +117,10 @@ impl PointCloudCropCommand {
|
||||
if let ExtendedEntityData::PointCloudEx(data) = &mut cloud.data {
|
||||
change(data);
|
||||
}
|
||||
CmdResult::UpdateEntityAndFinish { handle: self.handle, entity: EntityType::Extended(cloud) }
|
||||
CmdResult::UpdateEntityAndFinish {
|
||||
handle: self.handle,
|
||||
entity: EntityType::Extended(Box::new(cloud)),
|
||||
}
|
||||
}
|
||||
|
||||
fn axes(data: &PointCloudExData) -> glam::DMat3 {
|
||||
@@ -296,7 +299,7 @@ impl CadCommand for PointCloudCropCommand {
|
||||
match self.picked.take() {
|
||||
Some(EntityType::Extended(cloud)) if matches!(cloud.data, ExtendedEntityData::PointCloudEx(_)) => {
|
||||
self.handle = handle;
|
||||
self.cloud = Some(cloud);
|
||||
self.cloud = Some(*cloud);
|
||||
if self.uncrop {
|
||||
return self.finish(|data| data.croppings.clear());
|
||||
}
|
||||
|
||||
@@ -2793,7 +2793,7 @@ pub fn empty_extruded_surface(direction: DVec3, taper_angle: f64) -> EntityType
|
||||
options.is_solid = false;
|
||||
*sweep_vector = Vector3::new(direction.x, direction.y, direction.z);
|
||||
}
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
}
|
||||
|
||||
pub fn empty_revolved_surface(
|
||||
@@ -2832,7 +2832,7 @@ pub fn empty_revolved_surface(
|
||||
*stored_start = start_angle;
|
||||
*solid = false;
|
||||
}
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
}
|
||||
|
||||
// ── Autocomplete registry ─────────────────────────────────
|
||||
@@ -2909,7 +2909,7 @@ mod thicken_command_tests {
|
||||
let handle = Handle::new(42);
|
||||
let mut command = ThickenCommand::new(vec![
|
||||
(Handle::new(1), EntityType::Line(codec::entities::Line::default())),
|
||||
(handle, EntityType::Surface(codec::entities::Surface::new(codec::entities::SurfaceKind::Plane))),
|
||||
(handle, EntityType::Surface(Box::new(codec::entities::Surface::new(codec::entities::SurfaceKind::Plane)))),
|
||||
]);
|
||||
assert!(!command.is_selection_gathering());
|
||||
assert_eq!(command.handles, vec![handle]);
|
||||
|
||||
@@ -172,7 +172,7 @@ impl SectionPlaneCommand {
|
||||
self.kind == SectionKind::Slice,
|
||||
depth,
|
||||
);
|
||||
EntityType::Extended(entity)
|
||||
EntityType::Extended(Box::new(entity))
|
||||
}
|
||||
|
||||
fn line_at(&self, point: DVec3, viewing: DVec3, vertical_hint: DVec3) -> (Vec<DVec3>, DVec3) {
|
||||
|
||||
+18
-20
@@ -3052,10 +3052,10 @@ impl Scene {
|
||||
let is_insert = matches!(entity, EntityType::Insert(_));
|
||||
let is_section = matches!(
|
||||
entity,
|
||||
EntityType::Extended(codec::entities::ExtendedEntity {
|
||||
data: codec::entities::ExtendedEntityData::SectionObject(_),
|
||||
..
|
||||
})
|
||||
EntityType::Extended(extended) if matches!(
|
||||
extended.data,
|
||||
codec::entities::ExtendedEntityData::SectionObject(_)
|
||||
)
|
||||
);
|
||||
if self.meshes.contains_key(&handle)
|
||||
|| self.block_meshes.contains_key(&handle)
|
||||
@@ -7691,16 +7691,14 @@ impl Scene {
|
||||
CACHE_CATEGORY_MESH,
|
||||
|h| {
|
||||
self.meshes.contains_key(&h)
|
||||
|| matches!(
|
||||
self.document.get_entity(h),
|
||||
Some(EntityType::Insert(_))
|
||||
| Some(EntityType::Extended(
|
||||
codec::entities::ExtendedEntity {
|
||||
data: codec::entities::ExtendedEntityData::SectionObject(_),
|
||||
..
|
||||
}
|
||||
))
|
||||
)
|
||||
|| match self.document.get_entity(h) {
|
||||
Some(EntityType::Insert(_)) => true,
|
||||
Some(EntityType::Extended(extended)) => matches!(
|
||||
extended.data,
|
||||
codec::entities::ExtendedEntityData::SectionObject(_)
|
||||
),
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
) =>
|
||||
{
|
||||
@@ -12153,15 +12151,15 @@ mod section_tests {
|
||||
#[test]
|
||||
fn adding_and_erasing_a_section_keeps_its_object_graph_consistent() {
|
||||
let mut scene = Scene::new();
|
||||
let handle = scene.add_entity(EntityType::Extended(ExtendedEntity {
|
||||
let handle = scene.add_entity(EntityType::Extended(Box::new(ExtendedEntity {
|
||||
common: EntityCommon::new(),
|
||||
data: ExtendedEntityData::SectionObject(section(1, 0.0)),
|
||||
}));
|
||||
})));
|
||||
let settings_handle = match scene.document.get_entity(handle).unwrap() {
|
||||
EntityType::Extended(ExtendedEntity {
|
||||
data: ExtendedEntityData::SectionObject(data),
|
||||
..
|
||||
}) => data.settings_handle,
|
||||
EntityType::Extended(extended) => match &extended.data {
|
||||
ExtendedEntityData::SectionObject(data) => data.settings_handle,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
assert!(matches!(
|
||||
|
||||
@@ -91,5 +91,5 @@ pub fn surface_entity(record: &SolidHistoryLoft) -> EntityType {
|
||||
ruled_surface: settings.normals == 0, virtual_guide: false,
|
||||
cross_sections: Vec::new(), guide_curves: Vec::new(), path_curve: None,
|
||||
};
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
}
|
||||
@@ -109,5 +109,5 @@ pub fn swept_surface_entity(record: &SolidHistorySweep) -> EntityType {
|
||||
..SurfaceSweepOptions::default()
|
||||
},
|
||||
};
|
||||
EntityType::Surface(surface)
|
||||
EntityType::Surface(Box::new(surface))
|
||||
}
|
||||
@@ -1002,10 +1002,14 @@ impl Scene {
|
||||
continue;
|
||||
}
|
||||
let settings_handle = self.document.get_entity(h).and_then(|entity| match entity {
|
||||
EntityType::Extended(codec::entities::ExtendedEntity {
|
||||
data: codec::entities::ExtendedEntityData::SectionObject(data),
|
||||
..
|
||||
}) if !data.settings_handle.is_null() => Some(data.settings_handle),
|
||||
EntityType::Extended(extended) => match &extended.data {
|
||||
codec::entities::ExtendedEntityData::SectionObject(data)
|
||||
if !data.settings_handle.is_null() =>
|
||||
{
|
||||
Some(data.settings_handle)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
});
|
||||
let section_managers: Vec<Handle> = managers_by_section
|
||||
|
||||
Reference in new issue
Block a user