forked from 1b-agent/opencadstudio-upstream
Associative extruded, revolved and lofted surfaces; spline and ellipse sources
SURFACEASSOCIATIVITY now keeps EXTRUDE, REVOLVE and LOFT surfaces linked to their sources: the profile (and axis object) or cross sections are kept, the surface is made again when they change, and the drawing's associative network carries an action with the extruded, revolved or lofted surface action body, its path parameters and value parameters as the reference writes them. Swept, extruded, revolved and lofted surfaces can read splines (NURBS edge curve, fit-point splines through their fit points) and ellipses (elliptical edge curve). Associative surfaces of a file opened here follow their sources too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
aa0b87108c
commit
27bf35fc96
10 files changed
+661
-25
No files matched your search
@@ -42,6 +42,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
let pending = self.begin_undo(i, "EXTRUDE", handles.len(), true);
|
||||
let mut created_handles = Vec::new();
|
||||
let mut associative_sources = Vec::new();
|
||||
let mut consumed = Vec::new();
|
||||
let mut failed = 0usize;
|
||||
for handle in &handles {
|
||||
@@ -125,12 +126,27 @@ impl OpenCADStudio {
|
||||
entity.surface_data = data;
|
||||
}
|
||||
}
|
||||
match history {
|
||||
let created = match history {
|
||||
Some(history) => {
|
||||
self.add_surface_model_with_history(surface, body, history)
|
||||
}
|
||||
None => self.add_surface_model(surface, body),
|
||||
};
|
||||
// An associative surface keeps reading its profile.
|
||||
if sweep_model::surface_associativity() && path.is_none() && !created.is_null() {
|
||||
use crate::scene::model::surface_sources::{link_surface_sources, SurfaceSources};
|
||||
let (height, given) = match extent {
|
||||
ExtrudeExtent::Height(height) => (height, None),
|
||||
_ => (direction.length(), Some(direction)),
|
||||
};
|
||||
link_surface_sources(
|
||||
&mut self.tabs[i].scene.document,
|
||||
created,
|
||||
&SurfaceSources::Extrude { profile: *handle, height, direction: given, taper: taper_angle },
|
||||
);
|
||||
associative_sources.push(*handle);
|
||||
}
|
||||
created
|
||||
} else {
|
||||
let direction = direction.unwrap_or(glam::DVec3::ZERO);
|
||||
let history = path
|
||||
@@ -159,7 +175,7 @@ impl OpenCADStudio {
|
||||
failed += 1;
|
||||
} else {
|
||||
created_handles.push(created);
|
||||
if delete_sources {
|
||||
if delete_sources && !associative_sources.contains(handle) {
|
||||
consumed.push(*handle);
|
||||
}
|
||||
}
|
||||
@@ -319,6 +335,7 @@ impl OpenCADStudio {
|
||||
handles,
|
||||
axis_start,
|
||||
axis_end,
|
||||
axis_object,
|
||||
angle,
|
||||
start_angle,
|
||||
mode,
|
||||
@@ -355,6 +372,7 @@ impl OpenCADStudio {
|
||||
self.begin_undo(i, "REVOLVE", editable_handles.len(), true)
|
||||
};
|
||||
let mut created_handles = Vec::new();
|
||||
let mut associative_sources = Vec::new();
|
||||
let mut consumed = Vec::new();
|
||||
for handle in &editable_handles {
|
||||
let Some(entity) = self.tabs[i].scene.document.get_entity(*handle).cloned()
|
||||
@@ -374,7 +392,7 @@ impl OpenCADStudio {
|
||||
failed += 1;
|
||||
continue;
|
||||
};
|
||||
self.add_surface_model(
|
||||
let created = self.add_surface_model(
|
||||
empty_revolved_surface(
|
||||
&entity,
|
||||
axis_start,
|
||||
@@ -383,7 +401,25 @@ impl OpenCADStudio {
|
||||
start_angle,
|
||||
),
|
||||
body,
|
||||
)
|
||||
);
|
||||
// An associative surface keeps reading its profile and axis.
|
||||
if sweep_model::surface_associativity() && !created.is_null() {
|
||||
use crate::scene::model::surface_sources::{link_surface_sources, SurfaceSources};
|
||||
link_surface_sources(
|
||||
&mut self.tabs[i].scene.document,
|
||||
created,
|
||||
&SurfaceSources::Revolve {
|
||||
profile: *handle,
|
||||
axis: axis_object,
|
||||
start: axis_start,
|
||||
end: axis_end,
|
||||
angle,
|
||||
start_angle,
|
||||
},
|
||||
);
|
||||
associative_sources.push(*handle);
|
||||
}
|
||||
created
|
||||
} else {
|
||||
let result =
|
||||
sweep_model::revolve_history(&entity, from, to, angle, start_angle)
|
||||
@@ -410,7 +446,7 @@ impl OpenCADStudio {
|
||||
failed += 1;
|
||||
} else {
|
||||
created_handles.push(created);
|
||||
if delete_sources {
|
||||
if delete_sources && !associative_sources.contains(handle) {
|
||||
consumed.push(*handle);
|
||||
}
|
||||
}
|
||||
@@ -678,6 +714,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
let dirty_before = self.tabs[i].dirty;
|
||||
let pending = self.begin_undo(i, "LOFT", 1, true);
|
||||
let mut associative = false;
|
||||
let created = if surface {
|
||||
let handle = self.add_surface_model(
|
||||
loft_command_model::surface_entity(&record),
|
||||
@@ -688,6 +725,27 @@ impl OpenCADStudio {
|
||||
handle,
|
||||
codec::objects::SolidHistoryOperation::Loft(record),
|
||||
);
|
||||
// An associative surface keeps reading its cross
|
||||
// sections (each section a single object).
|
||||
let single: Option<Vec<Handle>> = sections
|
||||
.iter()
|
||||
.map(|section| match section {
|
||||
LoftSectionSelection::Entity(handle) => Some(*handle),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
if let Some(single) = single.filter(|_| {
|
||||
crate::scene::model::sweep_model::surface_associativity()
|
||||
&& guides.is_empty()
|
||||
&& path.is_none()
|
||||
}) {
|
||||
crate::scene::model::surface_sources::link_surface_sources(
|
||||
&mut self.tabs[i].scene.document,
|
||||
handle,
|
||||
&crate::scene::model::surface_sources::SurfaceSources::Loft { sections: single },
|
||||
);
|
||||
associative = true;
|
||||
}
|
||||
}
|
||||
handle
|
||||
} else {
|
||||
@@ -705,7 +763,7 @@ impl OpenCADStudio {
|
||||
self.command_line.push_error(crate::t!("LOFT could not create a complete display. The source sections were preserved.").as_ref());
|
||||
return Some(Task::none());
|
||||
} else {
|
||||
let mut consumed = if delete_sections {
|
||||
let mut consumed = if delete_sections && !associative {
|
||||
sources.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
|
||||
Reference in new issue
Block a user