forked from 1b-agent/opencadstudio-upstream
Merge pull request #1312 from ghost/ordered-tangent
This commit is contained in:
commit
dfe7904308
7 files changed
+431
-9
No files matched your search
+31
-3
@@ -3211,12 +3211,38 @@ impl Scene {
|
||||
retain_size: bool,
|
||||
retained_originals: &[(Handle, EntityType)],
|
||||
) {
|
||||
self.bump_entities_with_solve_policy(changes, driven_refs, retain_size, retained_originals, true);
|
||||
self.bump_entities_with_solve_policy(
|
||||
changes,
|
||||
driven_refs,
|
||||
retain_size,
|
||||
retained_originals,
|
||||
&[],
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
/// Refresh display and associations after a solved grip or exact history restore.
|
||||
pub(crate) fn bump_entities_after_parametric_solve(&mut self, changes: &[(Handle, ChangeKind)]) {
|
||||
self.bump_entities_with_solve_policy(changes, &[], false, &[], false);
|
||||
self.bump_entities_with_solve_policy(changes, &[], false, &[], &[], false);
|
||||
}
|
||||
|
||||
/// Apply a newly-created ordered relation while temporarily anchoring
|
||||
/// its reference side. The anchors guide only this first solve and are
|
||||
/// never added to the persistent constraint graph.
|
||||
pub fn bump_entities_with_initial_parametric_policy(
|
||||
&mut self,
|
||||
changes: &[(Handle, ChangeKind)],
|
||||
fixed_refs: &[parametric_constraints::ParametricRef],
|
||||
retain_size: bool,
|
||||
) {
|
||||
self.bump_entities_with_solve_policy(
|
||||
changes,
|
||||
&[],
|
||||
retain_size,
|
||||
&[],
|
||||
fixed_refs,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
fn bump_entities_with_solve_policy(
|
||||
@@ -3225,6 +3251,7 @@ impl Scene {
|
||||
driven_refs: &[parametric_constraints::ParametricRef],
|
||||
retain_size: bool,
|
||||
retained_originals: &[(Handle, EntityType)],
|
||||
fixed_refs: &[parametric_constraints::ParametricRef],
|
||||
solve_parametric: bool,
|
||||
) {
|
||||
if changes.iter().any(|(handle, kind)| {
|
||||
@@ -3260,11 +3287,12 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
if solve_parametric && !self.parametric_constraints.is_empty() {
|
||||
for change in self.refresh_parametric_constraints_with_originals(
|
||||
for change in self.refresh_parametric_constraints_with_initial_policy(
|
||||
&changes,
|
||||
driven_refs,
|
||||
retain_size,
|
||||
retained_originals,
|
||||
fixed_refs,
|
||||
) {
|
||||
if !changes.iter().any(|(handle, _)| *handle == change.0) {
|
||||
changes.push(change);
|
||||
|
||||
@@ -1904,6 +1904,7 @@ fn solve_scope(
|
||||
retain_size: bool,
|
||||
retain_lengths: bool,
|
||||
retained_before: &HashMap<Handle, std::sync::Arc<EntityType>>,
|
||||
initial_fixed_refs: &[ParametricRef],
|
||||
) -> Option<SolveResult> {
|
||||
let params = if set.local_parameters.is_empty() {
|
||||
drawing_params
|
||||
@@ -1960,6 +1961,36 @@ fn solve_scope(
|
||||
}
|
||||
}
|
||||
|
||||
// Ordered two-object constraints use the first pick as a reference for
|
||||
// their initial placement. Build temporary Fixed equations into this
|
||||
// solve only; they are deliberately omitted from `owner` and from the
|
||||
// persistent constraint set/native graph.
|
||||
for reference in initial_fixed_refs {
|
||||
let temporary = ParametricConstraint {
|
||||
id: ConstraintId::MAX,
|
||||
kind: ConstraintKind::Fixed,
|
||||
refs: vec![*reference],
|
||||
driving_param: None,
|
||||
enabled: true,
|
||||
native_origin: None,
|
||||
rigid_points: Vec::new(),
|
||||
distance_direction_type: distance_direction_type::UNDIRECTED,
|
||||
distance_direction: None,
|
||||
angle_sector: angle_sector::PARALLEL_COUNTERCLOCKWISE,
|
||||
};
|
||||
for constraint in build_constraint(
|
||||
document,
|
||||
&mut sys,
|
||||
&mut cache,
|
||||
params,
|
||||
&temporary,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
sys.add_constraint(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
let has_smooth = constraints.iter()
|
||||
.any(|constraint| constraint.enabled && constraint.kind == ConstraintKind::Smooth);
|
||||
if cache.is_empty() && !has_smooth {
|
||||
@@ -2090,6 +2121,12 @@ fn solve_scope(
|
||||
// endpoints. Other edits can retain line lengths as well.
|
||||
if retain_size {
|
||||
for (handle, geom) in &cache {
|
||||
if initial_fixed_refs
|
||||
.iter()
|
||||
.any(|reference| reference.entity == *handle)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
match geom {
|
||||
EntityGeom::Line(line) | EntityGeom::TextLine(line) if retain_lengths => {
|
||||
let current_length = {
|
||||
@@ -2145,12 +2182,32 @@ fn solve_scope(
|
||||
sys.add_constraint(Rc::new(Equal::new(circle.rad, target, 1.0)));
|
||||
}
|
||||
EntityGeom::Arc(arc) => {
|
||||
let (current_start, current_end) = {
|
||||
let store = sys.store();
|
||||
(store.get(arc.start_angle), store.get(arc.end_angle))
|
||||
};
|
||||
let radius = retained_before
|
||||
.get(handle)
|
||||
.and_then(|entity| retained_radius(entity))
|
||||
.unwrap_or_else(|| sys.store().get(arc.circle.rad));
|
||||
let target = sys.add_param(radius, true);
|
||||
sys.add_constraint(Rc::new(Equal::new(arc.circle.rad, target, 1.0)));
|
||||
let target_radius = sys.add_param(radius, true);
|
||||
let target_start = sys.add_param(current_start, true);
|
||||
let target_end = sys.add_param(current_end, true);
|
||||
sys.add_constraint(Rc::new(Equal::new(
|
||||
arc.circle.rad,
|
||||
target_radius,
|
||||
1.0,
|
||||
)));
|
||||
sys.add_constraint(Rc::new(Equal::new(
|
||||
arc.start_angle,
|
||||
target_start,
|
||||
1.0,
|
||||
)));
|
||||
sys.add_constraint(Rc::new(Equal::new(
|
||||
arc.end_angle,
|
||||
target_end,
|
||||
1.0,
|
||||
)));
|
||||
}
|
||||
EntityGeom::Ellipse(ellipse) => {
|
||||
let (focus_distance, minor_radius) = {
|
||||
@@ -2954,6 +3011,23 @@ impl Scene {
|
||||
driven_refs: &[ParametricRef],
|
||||
retain_size: bool,
|
||||
retained_originals: &[(Handle, EntityType)],
|
||||
) -> Vec<(Handle, ChangeKind)> {
|
||||
self.refresh_parametric_constraints_with_initial_policy(
|
||||
changes,
|
||||
driven_refs,
|
||||
retain_size,
|
||||
retained_originals,
|
||||
&[],
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn refresh_parametric_constraints_with_initial_policy(
|
||||
&mut self,
|
||||
changes: &[(Handle, ChangeKind)],
|
||||
driven_refs: &[ParametricRef],
|
||||
retain_size: bool,
|
||||
retained_originals: &[(Handle, EntityType)],
|
||||
initial_fixed_refs: &[ParametricRef],
|
||||
) -> Vec<(Handle, ChangeKind)> {
|
||||
// An erased entity takes its constraints with it instead of leaving
|
||||
// dangling references. Done first,
|
||||
@@ -3023,11 +3097,17 @@ impl Scene {
|
||||
retain_size,
|
||||
true,
|
||||
&retained_before,
|
||||
initial_fixed_refs,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
self.parametric_constraints[i].dof = Some(dof);
|
||||
self.parametric_constraints[i].conflicts = conflicts;
|
||||
if initial_fixed_refs.is_empty() {
|
||||
self.parametric_constraints[i].dof = Some(dof);
|
||||
self.parametric_constraints[i].conflicts = conflicts;
|
||||
} else {
|
||||
self.parametric_constraints[i].dof = None;
|
||||
self.parametric_constraints[i].conflicts.clear();
|
||||
}
|
||||
for (handle, new_entity) in solved {
|
||||
if let Some(before) = self.document.get_entity_arc(handle) {
|
||||
self.record_undo_before(handle, Some(before));
|
||||
@@ -3078,6 +3158,7 @@ impl Scene {
|
||||
retain_size,
|
||||
false,
|
||||
&retained_before,
|
||||
&[],
|
||||
)
|
||||
else {
|
||||
continue;
|
||||
|
||||
Reference in new issue
Block a user