forked from 1b-agent/opencadstudio-upstream
Merge pull request #1679 from ramox81/codex/surface-associativity-sources
Associative extruded, revolved and lofted surfaces; spline and ellipse sources # Conflicts: # src/app/command_driver/solid3d.rs # src/scene/dwg_native_constraints.rs # src/scene/model/mod.rs # src/scene/model/sweep_command_model.rs # src/scene/model/sweep_model.rs # src/scene/modify.rs
This commit is contained in:
commit
5bb0efd93e
12 files changed
+1106
-228
No files matched your search
+420
-148
@@ -2652,19 +2652,396 @@ fn pending_swept_surfaces(document: &CadDocument) -> Vec<(Handle, Handle, Handle
|
||||
let (profile, path) = sweep_model::sweep_sources(entity)?;
|
||||
let surface = entity.common().handle;
|
||||
(!carried.contains(&surface)
|
||||
&& document
|
||||
.get_entity(profile)
|
||||
.is_some_and(|e| sweep_model::assoc_edge_curve(e).is_some())
|
||||
&& document
|
||||
.get_entity(path)
|
||||
.is_some_and(|e| sweep_model::assoc_edge_curve(e).is_some()))
|
||||
.then_some((surface, profile, path))
|
||||
&& document.get_entity(profile).is_some_and(|e| sweep_model::assoc_source_supported(e))
|
||||
&& document.get_entity(path).is_some_and(|e| sweep_model::assoc_source_supported(e)))
|
||||
.then_some((surface, profile, path))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
pending.sort_by_key(|(surface, _, _)| surface.value());
|
||||
pending
|
||||
}
|
||||
|
||||
/// Associative extruded, revolved and lofted surfaces made here that the
|
||||
/// drawing's network does not carry yet, with their sources.
|
||||
fn pending_source_surfaces(
|
||||
document: &CadDocument,
|
||||
) -> Vec<(Handle, crate::scene::model::surface_sources::SurfaceSources)> {
|
||||
use crate::scene::model::{surface_sources, sweep_model};
|
||||
let carried: Vec<Handle> = document
|
||||
.objects
|
||||
.keys()
|
||||
.filter_map(|handle| action_surface(document, *handle))
|
||||
.collect();
|
||||
let mut pending = document
|
||||
.entities()
|
||||
.filter(|entity| matches!(entity, codec::EntityType::Surface(_)))
|
||||
.filter_map(|entity| {
|
||||
let sources = surface_sources::surface_sources(entity)?;
|
||||
let surface = entity.common().handle;
|
||||
(!carried.contains(&surface)
|
||||
&& sources.handles().iter().all(|handle| {
|
||||
document.get_entity(*handle).is_some_and(|e| sweep_model::assoc_source_supported(e))
|
||||
}))
|
||||
.then_some((surface, sources))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
pending.sort_by_key(|(surface, _)| surface.value());
|
||||
pending
|
||||
}
|
||||
|
||||
/// Whether the drawing has associative surfaces its network has to carry.
|
||||
fn has_pending_surfaces(document: &CadDocument) -> bool {
|
||||
!pending_swept_surfaces(document).is_empty() || !pending_source_surfaces(document).is_empty()
|
||||
}
|
||||
|
||||
/// Named-objects dictionary key of the drawing's persistent subentity manager.
|
||||
const SUBENT_MANAGER_KEY: &str = "ACAD_ASSOCPERSSUBENTMANAGER";
|
||||
|
||||
/// A read dependency of an action on `dependent_on`.
|
||||
fn read_dependency(dependent_on: Handle, id: i32) -> AssocDependency {
|
||||
AssocDependency {
|
||||
class_version: 2,
|
||||
status: 0,
|
||||
is_read_dependency: true,
|
||||
is_write_dependency: false,
|
||||
is_attached_to_object: true,
|
||||
is_delegating_to_owning_action: true,
|
||||
order: 0,
|
||||
dependent_on,
|
||||
name: None,
|
||||
read_dependency: Handle::NULL,
|
||||
node: Handle::NULL,
|
||||
dependency_body: Handle::NULL,
|
||||
dependency_body_id: id,
|
||||
}
|
||||
}
|
||||
|
||||
/// An edge action parameter reading `curve` through dependency `read`.
|
||||
fn edge_action_param(read: Handle, (action_type, subcurve_kind, curve): crate::scene::model::sweep_model::AssocCurve) -> AssociativeData {
|
||||
use codec::objects::{AssocActionParam, AssocEdgeActionParam, AssocSingleDependencyActionParam};
|
||||
AssociativeData::EdgeActionParam(AssocEdgeActionParam {
|
||||
single_dependency: AssocSingleDependencyActionParam {
|
||||
action_param: AssocActionParam { is_r2013: 1, version: 0, name: String::new() },
|
||||
dependency_class_version: 0,
|
||||
dependency: read,
|
||||
class_version: 0,
|
||||
},
|
||||
parameter: Handle::NULL,
|
||||
has_action: true,
|
||||
action_type,
|
||||
subcurve_kind,
|
||||
curve,
|
||||
})
|
||||
}
|
||||
|
||||
/// The subentity manager's record of a region's edges: one entry per edge
|
||||
/// id from `first_id`, in the order the region's dependencies read them,
|
||||
/// each naming the edge (and, between edges, its two vertices) by the
|
||||
/// region's face and edge numbers. `loops` holds each loop's edge count.
|
||||
fn region_subent_entries(loops: &[usize], step: i32, first_id: i32) -> Vec<i32> {
|
||||
const BODY: i32 = 1_000_000_000;
|
||||
const FACE: i32 = 1001;
|
||||
let mut values = Vec::new();
|
||||
let (mut id, mut offset) = (first_id, 0usize);
|
||||
for &count in loops {
|
||||
let edge = |index: usize| 51001 + 100_000 * (offset + index % count) as i32;
|
||||
let vertex = |a: i32, b: i32| [1, 3, 1, BODY, FACE, 1, BODY, a, 1, BODY, b, 0, 0, 0, 900, 0, 900, 0, 0];
|
||||
for read in 0..count {
|
||||
if count == 1 {
|
||||
values.extend([4, 0, 5, id, step, step, 0, 0, 24, 0, 0, 1, BODY, edge(0), 0, 0, 1, 1, BODY, FACE]);
|
||||
values.extend([0; 14]);
|
||||
} else {
|
||||
// The dependencies start at the loop's second edge.
|
||||
let index = read + 1;
|
||||
values.extend([4, 0, 11, id, step, step, 0, 2, 2, 2, 0, 2, 2, 2, 54, 0, 0, 1, BODY, edge(index)]);
|
||||
values.extend([0, 0, 1, 1, BODY, FACE, 0, 0, 0, 0]);
|
||||
values.extend(vertex(edge(index), edge(index + count - 1)));
|
||||
values.extend([0, 0]);
|
||||
values.extend(vertex(edge(index + 1), edge(index)));
|
||||
}
|
||||
id += 1;
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
values
|
||||
}
|
||||
|
||||
/// Records a region read by an action in the drawing's persistent
|
||||
/// subentity manager (made when the drawing has none): a step for the
|
||||
/// action and one for the region, then one id per edge. The manager keeps
|
||||
/// the last id given, its edge entries and the list of every id given.
|
||||
/// Returns the edges' ids, or `None` when the drawing's manager has a form
|
||||
/// this cannot extend.
|
||||
fn register_region_subents(document: &mut CadDocument, loops: &[usize]) -> Option<Vec<i32>> {
|
||||
use codec::objects::AssocPersSubentManager;
|
||||
let root = document.header.named_objects_dict_handle;
|
||||
let existing = match document.objects.get(&root) {
|
||||
Some(ObjectType::Dictionary(dictionary)) => dictionary.get(SUBENT_MANAGER_KEY),
|
||||
_ => return None,
|
||||
};
|
||||
let current = existing.and_then(|handle| match document.objects.get(&handle) {
|
||||
Some(ObjectType::Associative(AssociativeObject { data: AssociativeData::PersSubentManager(manager), .. })) => {
|
||||
Some((handle, manager.values.clone()))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let (handle, last, count, mut entries) = match current {
|
||||
Some((handle, values)) => {
|
||||
let last = *values.first()?;
|
||||
if values.len() == 4 && values[1..].iter().all(|value| *value == 0) {
|
||||
(handle, last, 0, Vec::new())
|
||||
} else {
|
||||
let tail = usize::try_from(last).ok()? + 3;
|
||||
if values.len() < tail + 2 || values[values.len() - tail] != last {
|
||||
return None;
|
||||
}
|
||||
(handle, last, values[1], values[2..values.len() - tail].to_vec())
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let handle = document.allocate_handle();
|
||||
set_dictionary_entry(document, root, SUBENT_MANAGER_KEY, handle);
|
||||
(handle, 0, 0, Vec::new())
|
||||
}
|
||||
};
|
||||
let edges = loops.iter().sum::<usize>() as i32;
|
||||
let first = last + 3;
|
||||
entries.extend(region_subent_entries(loops, last + 2, first));
|
||||
let last = last + 2 + edges;
|
||||
let mut values = vec![last, count + edges];
|
||||
values.extend(entries);
|
||||
values.push(last);
|
||||
values.extend(1..=last);
|
||||
values.extend([0, 0]);
|
||||
document.objects.insert(handle, ObjectType::Associative(AssociativeObject {
|
||||
handle,
|
||||
owner: root,
|
||||
reactors: vec![root],
|
||||
dxf_name: "ACDBASSOCPERSSUBENTMANAGER".to_string(),
|
||||
cpp_class_name: "AcDbAssocPersSubentManager".to_string(),
|
||||
data: AssociativeData::PersSubentManager(AssocPersSubentManager {
|
||||
class_version: 2,
|
||||
markers: [3, 0, 2],
|
||||
values,
|
||||
final_flag: false,
|
||||
}),
|
||||
..Default::default()
|
||||
}));
|
||||
Some((first..first + edges).collect())
|
||||
}
|
||||
|
||||
/// How an action reads one source through `parameter`: one read dependency
|
||||
/// on a curve; on a region one geometry dependency per edge, naming the
|
||||
/// edge by its persistent subentity id and chained on the region. Adds the
|
||||
/// dependencies (owned by `action`) and edge parameters to `objects` with
|
||||
/// ids from `first_id`; returns (edge parameter, dependency) pairs.
|
||||
fn source_reads(
|
||||
document: &mut CadDocument,
|
||||
action: Handle,
|
||||
parameter: Handle,
|
||||
source: Handle,
|
||||
first_id: i32,
|
||||
objects: &mut Vec<(Handle, Handle, &'static str, &'static str, AssociativeData)>,
|
||||
) -> Option<Vec<(Handle, Handle)>> {
|
||||
use crate::scene::model::sweep_model;
|
||||
let entity = document.get_entity(source)?;
|
||||
let Some(loops) = sweep_model::region_edge_curves(entity) else {
|
||||
let curve = sweep_model::assoc_edge_curve(entity)?;
|
||||
let (edge, read) = (document.allocate_handle(), document.allocate_handle());
|
||||
objects.push((edge, parameter, "ACDBASSOCEDGEACTIONPARAM", "AcDbAssocEdgeActionParam", edge_action_param(read, curve)));
|
||||
objects.push((read, action, "ACDBASSOCDEPENDENCY", "AcDbAssocDependency",
|
||||
AssociativeData::Dependency(read_dependency(source, first_id))));
|
||||
return Some(vec![(edge, read)]);
|
||||
};
|
||||
let sizes = loops.iter().map(Vec::len).collect::<Vec<_>>();
|
||||
let ids = register_region_subents(document, &sizes)?;
|
||||
// The region carries the step its edge names belong to; without it (and
|
||||
// without named edges in its modeler data) the reference cannot find
|
||||
// the edges again.
|
||||
crate::scene::view::dispatch::set_entity_xdata(document, source, "ACAD_STEPID",
|
||||
Some(vec![codec::xdata::XDataValue::Integer32(ids.first()? - 1)]));
|
||||
let curves = loops.into_iter().flatten().collect::<Vec<_>>();
|
||||
let pairs = curves.iter().map(|_| (document.allocate_handle(), document.allocate_handle())).collect::<Vec<_>>();
|
||||
for (index, (curve, (edge, read))) in curves.into_iter().zip(pairs.iter().copied()).enumerate() {
|
||||
let mut dependency = read_dependency(source, first_id + index as i32);
|
||||
dependency.read_dependency = index.checked_sub(1).map_or(Handle::NULL, |previous| pairs[previous].1);
|
||||
dependency.node = pairs.get(index + 1).map_or(Handle::NULL, |next| next.1);
|
||||
objects.push((edge, parameter, "ACDBASSOCEDGEACTIONPARAM", "AcDbAssocEdgeActionParam", edge_action_param(read, curve)));
|
||||
objects.push((read, action, "ACDBASSOCGEOMDEPENDENCY", "AcDbAssocGeomDependency",
|
||||
AssociativeData::GeomDependency(AssocGeomDependency {
|
||||
dependency,
|
||||
class_version: 0,
|
||||
enabled: true,
|
||||
persistent_subent: AssocPersistentSubentId {
|
||||
class_name: "AcDbAssocAsmBasedEntityPersSubentId".to_string(),
|
||||
dependent_on_compound_object: false,
|
||||
class_code: 5,
|
||||
values: vec![0, 2, ids[index]],
|
||||
leading_flag: false,
|
||||
},
|
||||
})));
|
||||
}
|
||||
Some(pairs)
|
||||
}
|
||||
|
||||
/// The reference's associative network for each pending extruded, revolved
|
||||
/// or lofted surface: an action with the matching surface action body that
|
||||
/// writes the surface and reads its sources through path parameters (an
|
||||
/// empty one for a revolve axis given by points and for a loft without a
|
||||
/// path), with the surface's values as value parameters. Returns the
|
||||
/// network's new actions in order.
|
||||
fn materialize_source_surface_actions(
|
||||
allocator: &mut Allocator,
|
||||
network: Handle,
|
||||
pending: &[(Handle, crate::scene::model::surface_sources::SurfaceSources)],
|
||||
first_index: i32,
|
||||
) -> Vec<Handle> {
|
||||
use crate::scene::model::surface_sources::SurfaceSources;
|
||||
use codec::objects::*;
|
||||
let mut added = Vec::new();
|
||||
for (surface, sources) in pending.iter() {
|
||||
let surface = *surface;
|
||||
let document = &*allocator.document;
|
||||
// The value parameters: name, unit type, values, and whether they
|
||||
// control the surface.
|
||||
let real = |value: f64| AssocEvalVariant { code: 40, value: AssocEvalValue::Real(value) };
|
||||
let short = |value: i32| AssocEvalVariant { code: 70, value: AssocEvalValue::Short(value as i16) };
|
||||
let (kind, class, dxf, values, params): (
|
||||
AssocSurfaceActionKind,
|
||||
&str,
|
||||
&str,
|
||||
Vec<(&str, i32, Vec<AssocEvalVariant>, bool)>,
|
||||
Vec<(&str, Option<Handle>)>,
|
||||
) = match sources {
|
||||
SurfaceSources::Extrude { profile, height, taper, .. } => (
|
||||
AssocSurfaceActionKind::Extruded,
|
||||
"AcDbAssocExtrudedSurfaceActionBody",
|
||||
"ACDBASSOCEXTRUDEDSURFACEACTIONBODY",
|
||||
vec![("ExtrusionHeight", 1, vec![real(*height)], true), ("ExtrusionTaperAngle", 2, vec![real(*taper)], true)],
|
||||
vec![("ExtrudeProfile", Some(*profile))],
|
||||
),
|
||||
SurfaceSources::Revolve { profile, axis, angle, .. } => (
|
||||
AssocSurfaceActionKind::Revolved,
|
||||
"AcDbAssocRevolvedSurfaceActionBody",
|
||||
"ACDBASSOCREVOLVEDSURFACEACTIONBODY",
|
||||
vec![("RevolveAngle", 2, vec![real(*angle)], true)],
|
||||
vec![("RevolveProfile", Some(*profile)), ("RevolvePath", *axis)],
|
||||
),
|
||||
SurfaceSources::Loft { sections } => {
|
||||
let loft = document.solid_history_operations(surface).and_then(|operations| {
|
||||
operations.into_iter().find_map(|operation| match operation {
|
||||
SolidHistoryOperation::Loft(record) => record.parameters,
|
||||
_ => None,
|
||||
})
|
||||
});
|
||||
let (continuity, bulge) = loft.map_or(((1, 1), (0.5, 0.5)), |p| {
|
||||
((p.start_continuity, p.end_continuity), (p.start_bulge, p.end_bulge))
|
||||
});
|
||||
(
|
||||
AssocSurfaceActionKind::Lofted,
|
||||
"AcDbAssocLoftedSurfaceActionBody",
|
||||
"ACDBASSOCLOFTEDSURFACEACTIONBODY",
|
||||
// One value per cross section: the start and end
|
||||
// settings at the ends, the defaults between them.
|
||||
vec![
|
||||
("Continuity", 0, (0..sections.len()).map(|index| short(if index == 0 { continuity.0 } else if index + 1 == sections.len() { continuity.1 } else { 1 })).collect(), false),
|
||||
("Bulge", 0, (0..sections.len()).map(|index| real(if index == 0 { bulge.0 } else if index + 1 == sections.len() { bulge.1 } else { 0.5 })).collect(), false),
|
||||
],
|
||||
sections.iter().map(|section| ("CrossSection", Some(*section)))
|
||||
.chain(std::iter::once(("PathCurve", None)))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let document = &mut *allocator.document;
|
||||
let (action, body, written) = (document.allocate_handle(), document.allocate_handle(), document.allocate_handle());
|
||||
let mut objects: Vec<(Handle, Handle, &'static str, &'static str, AssociativeData)> = Vec::new();
|
||||
let mut reactors: Vec<(Handle, Handle)> = vec![(surface, written)];
|
||||
let mut dependencies = vec![written];
|
||||
let mut owned = Vec::new();
|
||||
let mut writes = read_dependency(surface, 1);
|
||||
(writes.is_read_dependency, writes.is_write_dependency, writes.order) = (false, true, i32::MIN);
|
||||
objects.push((written, action, "ACDBASSOCDEPENDENCY", "AcDbAssocDependency", AssociativeData::Dependency(writes)));
|
||||
let mut complete = true;
|
||||
for (name, source) in params.iter() {
|
||||
let parameter = document.allocate_handle();
|
||||
let mut children = Vec::new();
|
||||
if let Some(source) = source {
|
||||
let Some(reads) = source_reads(document, action, parameter, *source, dependencies.len() as i32 + 1, &mut objects) else {
|
||||
complete = false;
|
||||
break;
|
||||
};
|
||||
for (edge, read) in reads {
|
||||
reactors.push((*source, read));
|
||||
dependencies.push(read);
|
||||
children.push(edge);
|
||||
}
|
||||
}
|
||||
objects.push((parameter, action, "ACDBASSOCPATHACTIONPARAM", "AcDbAssocPathActionParam",
|
||||
AssociativeData::PathActionParam(AssocPathActionParam {
|
||||
compound: AssocCompoundActionParam {
|
||||
action_param: AssocActionParam { is_r2013: 1, version: 0, name: name.to_string() },
|
||||
class_version: 0,
|
||||
status: 0,
|
||||
parameters: children,
|
||||
child_parameter: None,
|
||||
},
|
||||
version: 0,
|
||||
})));
|
||||
owned.push(parameter);
|
||||
}
|
||||
if !complete {
|
||||
continue;
|
||||
}
|
||||
objects.push((action, network, "ACDBASSOCACTION", "AcDbAssocAction", AssociativeData::Action(AssocAction {
|
||||
class_version: 2,
|
||||
geometry_status: 0,
|
||||
owning_network: network,
|
||||
action_body: body,
|
||||
action_index: 0,
|
||||
max_dependency_index: dependencies.len() as i32,
|
||||
dependencies: dependencies.iter().map(|handle| AssocActionDependency { is_owned: true, dependency: *handle }).collect(),
|
||||
owned_parameters: owned,
|
||||
values: values
|
||||
.into_iter()
|
||||
.map(|(name, unit_type, amounts, controls)| AssocValueParam {
|
||||
class_version: 0,
|
||||
name: name.to_string(),
|
||||
unit_type,
|
||||
variables: amounts.into_iter().map(|value| AssocValueParamVariable { value, handle: Handle::NULL }).collect(),
|
||||
controlled_object_dependency: if controls { written } else { Handle::NULL },
|
||||
})
|
||||
.collect(),
|
||||
})));
|
||||
objects.push((body, action, dxf, class, AssociativeData::SurfaceActionBody(AssocSurfaceActionBody {
|
||||
kind,
|
||||
action_body: AssocActionBody { version: 2 },
|
||||
surface_body: AssocSurfaceBody { version: 0, dependency: written, is_semi_associative: false, marker: 1, is_semi_override: false, grip_status: 0 },
|
||||
..Default::default()
|
||||
})));
|
||||
for (handle, owner, dxf, class, data) in objects {
|
||||
allocator.insert_associative_at(handle, owner, dxf, class, data);
|
||||
}
|
||||
for (target, reactor) in reactors {
|
||||
let document = &mut *allocator.document;
|
||||
if let Some(entity) = document.get_entity_mut(target) {
|
||||
entity.common_mut().reactors.push(reactor);
|
||||
} else if let Some(ObjectType::Associative(object)) = document.objects.get_mut(&target) {
|
||||
object.reactors.push(reactor);
|
||||
}
|
||||
}
|
||||
added.push(action);
|
||||
}
|
||||
for (offset, handle) in added.iter().copied().enumerate() {
|
||||
if let Some(ObjectType::Associative(AssociativeObject { data: AssociativeData::Action(action), .. })) =
|
||||
allocator.document.objects.get_mut(&handle)
|
||||
{
|
||||
action.action_index = first_index + offset as i32 + 1;
|
||||
}
|
||||
}
|
||||
added
|
||||
}
|
||||
|
||||
/// The names an expression reads.
|
||||
fn expression_names(expression: &str) -> Vec<String> {
|
||||
let mut names = Vec::new();
|
||||
@@ -2717,16 +3094,6 @@ fn materialize_swept_surface_actions(
|
||||
options.twist_angle,
|
||||
);
|
||||
let expressions = sweep_model::sweep_expressions(surface_entity).unwrap_or([None, None]);
|
||||
let (Some(profile_curve), Some(path_curve)) = (
|
||||
document
|
||||
.get_entity(profile)
|
||||
.and_then(sweep_model::assoc_edge_curve),
|
||||
document
|
||||
.get_entity(path)
|
||||
.and_then(sweep_model::assoc_edge_curve),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
let evaluate = |expression: &str| {
|
||||
let mut table = parameters.clone();
|
||||
table.set("sweepExpression", expression).ok()?;
|
||||
@@ -2737,27 +3104,7 @@ fn materialize_swept_surface_actions(
|
||||
};
|
||||
let document = &mut *allocator.document;
|
||||
let mut next = || document.allocate_handle();
|
||||
let (
|
||||
action,
|
||||
body,
|
||||
written,
|
||||
profile_param,
|
||||
profile_edge,
|
||||
profile_read,
|
||||
path_param,
|
||||
path_edge,
|
||||
path_read,
|
||||
) = (
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
next(),
|
||||
);
|
||||
let (action, body, written, profile_param, path_param) = (next(), next(), next(), next(), next());
|
||||
let dependency = |dependent_on: Handle, read: bool, id: i32, order: i32| AssocDependency {
|
||||
class_version: 2,
|
||||
status: 0,
|
||||
@@ -2773,13 +3120,15 @@ fn materialize_swept_surface_actions(
|
||||
dependency_body: Handle::NULL,
|
||||
dependency_body_id: id,
|
||||
};
|
||||
let mut objects: Vec<(Handle, Handle, &str, &str, AssociativeData)> = Vec::new();
|
||||
let mut reactors: Vec<(Handle, Handle)> = vec![
|
||||
(surface, written),
|
||||
(profile, profile_read),
|
||||
(path, path_read),
|
||||
];
|
||||
let mut dependencies = vec![written, profile_read, path_read];
|
||||
let mut objects: Vec<(Handle, Handle, &'static str, &'static str, AssociativeData)> = Vec::new();
|
||||
// The profile (a region by its edges) and the path, read in that order.
|
||||
let Some(profile_reads) = source_reads(document, action, profile_param, profile, 2, &mut objects) else { continue };
|
||||
let Some(path_reads) = source_reads(document, action, path_param, path, profile_reads.len() as i32 + 2, &mut objects) else { continue };
|
||||
let mut reactors: Vec<(Handle, Handle)> = vec![(surface, written)];
|
||||
reactors.extend(profile_reads.iter().map(|(_, read)| (profile, *read)));
|
||||
reactors.extend(path_reads.iter().map(|(_, read)| (path, *read)));
|
||||
let mut dependencies = vec![written];
|
||||
dependencies.extend(profile_reads.iter().chain(&path_reads).map(|(_, read)| *read));
|
||||
let mut value_handles = [Handle::NULL, Handle::NULL];
|
||||
let mut network_actions = vec![action];
|
||||
// Scale (slot 0) and twist (slot 1) expressions.
|
||||
@@ -2916,94 +3265,22 @@ fn materialize_swept_surface_actions(
|
||||
grip_status: 0,
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
objects.push((
|
||||
written,
|
||||
action,
|
||||
"ACDBASSOCDEPENDENCY",
|
||||
"AcDbAssocDependency",
|
||||
AssociativeData::Dependency(dependency(surface, false, 1, i32::MIN)),
|
||||
));
|
||||
let edge_param =
|
||||
|read: Handle,
|
||||
(kind, subcurve, curve): (i32, AssocSubcurveKind, Vec<AssocCurveValue>)| {
|
||||
AssociativeData::EdgeActionParam(AssocEdgeActionParam {
|
||||
single_dependency: AssocSingleDependencyActionParam {
|
||||
action_param: AssocActionParam {
|
||||
is_r2013: 1,
|
||||
version: 0,
|
||||
name: String::new(),
|
||||
},
|
||||
dependency_class_version: 0,
|
||||
dependency: read,
|
||||
class_version: 0,
|
||||
},
|
||||
parameter: Handle::NULL,
|
||||
has_action: true,
|
||||
action_type: kind,
|
||||
subcurve_kind: subcurve,
|
||||
curve,
|
||||
})
|
||||
};
|
||||
let path_parameter = |name: &str, child: Handle| {
|
||||
AssociativeData::PathActionParam(AssocPathActionParam {
|
||||
compound: AssocCompoundActionParam {
|
||||
action_param: AssocActionParam {
|
||||
is_r2013: 1,
|
||||
version: 0,
|
||||
name: name.to_string(),
|
||||
},
|
||||
class_version: 0,
|
||||
status: 0,
|
||||
parameters: vec![child],
|
||||
child_parameter: None,
|
||||
},
|
||||
version: 0,
|
||||
})
|
||||
};
|
||||
objects.push((
|
||||
profile_param,
|
||||
action,
|
||||
"ACDBASSOCPATHACTIONPARAM",
|
||||
"AcDbAssocPathActionParam",
|
||||
path_parameter("SweepProfile", profile_edge),
|
||||
));
|
||||
objects.push((
|
||||
profile_edge,
|
||||
profile_param,
|
||||
"ACDBASSOCEDGEACTIONPARAM",
|
||||
"AcDbAssocEdgeActionParam",
|
||||
edge_param(profile_read, profile_curve),
|
||||
));
|
||||
objects.push((
|
||||
profile_read,
|
||||
action,
|
||||
"ACDBASSOCDEPENDENCY",
|
||||
"AcDbAssocDependency",
|
||||
AssociativeData::Dependency(dependency(profile, true, 2, 0)),
|
||||
));
|
||||
objects.push((
|
||||
path_param,
|
||||
action,
|
||||
"ACDBASSOCPATHACTIONPARAM",
|
||||
"AcDbAssocPathActionParam",
|
||||
path_parameter("SweepPath", path_edge),
|
||||
));
|
||||
objects.push((
|
||||
path_edge,
|
||||
path_param,
|
||||
"ACDBASSOCEDGEACTIONPARAM",
|
||||
"AcDbAssocEdgeActionParam",
|
||||
edge_param(path_read, path_curve),
|
||||
));
|
||||
objects.push((
|
||||
path_read,
|
||||
action,
|
||||
"ACDBASSOCDEPENDENCY",
|
||||
"AcDbAssocDependency",
|
||||
AssociativeData::Dependency(dependency(path, true, 3, 0)),
|
||||
));
|
||||
})));
|
||||
objects.push((written, action, "ACDBASSOCDEPENDENCY", "AcDbAssocDependency", AssociativeData::Dependency(dependency(surface, false, 1, i32::MIN))));
|
||||
let path_parameter = |name: &str, children: Vec<Handle>| AssociativeData::PathActionParam(AssocPathActionParam {
|
||||
compound: AssocCompoundActionParam {
|
||||
action_param: AssocActionParam { is_r2013: 1, version: 0, name: name.to_string() },
|
||||
class_version: 0,
|
||||
status: 0,
|
||||
parameters: children,
|
||||
child_parameter: None,
|
||||
},
|
||||
version: 0,
|
||||
});
|
||||
objects.push((profile_param, action, "ACDBASSOCPATHACTIONPARAM", "AcDbAssocPathActionParam",
|
||||
path_parameter("SweepProfile", profile_reads.iter().map(|(edge, _)| *edge).collect())));
|
||||
objects.push((path_param, action, "ACDBASSOCPATHACTIONPARAM", "AcDbAssocPathActionParam",
|
||||
path_parameter("SweepPath", path_reads.iter().map(|(edge, _)| *edge).collect())));
|
||||
for (handle, owner, dxf, class, data) in objects {
|
||||
allocator.insert_associative_at(handle, owner, dxf, class, data);
|
||||
}
|
||||
@@ -3180,7 +3457,7 @@ fn materialize_scope(
|
||||
&& existing_variables.is_empty()
|
||||
&& preserved_groups.is_empty()
|
||||
&& foreign_actions.is_empty()
|
||||
&& !(materialize_all_parameters && !pending_swept_surfaces(document).is_empty())
|
||||
&& !(materialize_all_parameters && has_pending_surfaces(document))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -3365,18 +3642,14 @@ fn materialize_scope(
|
||||
}
|
||||
}
|
||||
refresh_foreign_values(allocator.document, &foreign_actions, parameters);
|
||||
let pending = if materialize_all_parameters {
|
||||
pending_swept_surfaces(allocator.document)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let surface_actions = materialize_swept_surface_actions(
|
||||
&mut allocator,
|
||||
network_handle,
|
||||
parameters,
|
||||
&pending,
|
||||
first_foreign + foreign_actions.len() as i32,
|
||||
);
|
||||
let pending = if materialize_all_parameters { pending_swept_surfaces(allocator.document) } else { Vec::new() };
|
||||
let mut surface_actions = materialize_swept_surface_actions(
|
||||
&mut allocator, network_handle, parameters, &pending, first_foreign + foreign_actions.len() as i32);
|
||||
let pending_sources = if materialize_all_parameters { pending_source_surfaces(allocator.document) } else { Vec::new() };
|
||||
let source_actions = materialize_source_surface_actions(
|
||||
&mut allocator, network_handle, &pending_sources,
|
||||
first_foreign + (foreign_actions.len() + surface_actions.len()) as i32);
|
||||
surface_actions.extend(source_actions);
|
||||
|
||||
let network = AssocNetwork {
|
||||
action: AssocAction {
|
||||
@@ -3537,8 +3810,7 @@ impl Scene {
|
||||
if set.is_none()
|
||||
&& !existing
|
||||
&& (owner != model_owner
|
||||
|| (self.named_parameters.is_empty()
|
||||
&& pending_swept_surfaces(&self.document).is_empty()))
|
||||
|| (self.named_parameters.is_empty() && !has_pending_surfaces(&self.document)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user