Add 8 geometric constraint kinds and an opt-in DWG-native persistence toggle

New ConstraintKind variants — Concentric, CenterPoint, Colinear, Midpoint,
Fixed, PointOnCurve, EqualDistance, Symmetric — each built entirely from
existing ocs_gcs (FreeCAD planegcs) primitives, no new solver math needed.
build_constraint now returns Vec<Rc<dyn Constraint>> instead of
Option<Rc<...>>, generalizing the old Coincident-only "needs a second
system-level constraint" special case to every kind that needs one.
Wired into the ribbon (7 new buttons), a new point+pre-selected-entity
command for CenterPoint/Midpoint/PointOnCurve, a new 4-point command for
EqualDistance, and the existing DWG-native class-name mapping (all 8 reuse
the same generic "plain Geometrical node" path already built for
Coincident/Horizontal/etc.). Deliberately not modeled: Normal and
EqualCurvature, which for this app's Line/Circle-only entity model would
just be Perpendicular and Equal wearing different DWG class names.

Also makes DWG-native constraint persistence opt-in (Options > General,
off by default) rather than unconditional: a scope that doesn't yet have
the native graph is only given one when the setting is on, but a scope
that already has one — from an earlier save, or a file that came from
real AutoCAD — keeps getting it resynced regardless of the setting, so
toggling it off never freezes a stale graph in place.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Felix RiestraandClaude Sonnet 5 committed 2026-09-09 19:38:31 +02:00
1 parent cf33a1d019
commit 31b5ef4ec3
18 files changed
+1076 -106

No files matched your search

+4 -2
View File
@@ -393,6 +393,7 @@ impl OpenCADStudio {
textfill: crate::scene::text::sdf_atlas::textfill(),
backup_on_save: self.backup_on_save,
file_assoc_enabled: self.file_assoc_enabled,
write_dwg_native_constraints: self.write_dwg_native_constraints,
savetime_min: self.savetime_min,
default_save_format: self.default_save_format.clone(),
pick_add: self.pick_add,
@@ -459,6 +460,7 @@ impl OpenCADStudio {
crate::scene::text::sdf_atlas::set_textfill(s.textfill);
self.backup_on_save = s.backup_on_save;
self.file_assoc_enabled = s.file_assoc_enabled;
self.write_dwg_native_constraints = s.write_dwg_native_constraints;
self.savetime_min = s.savetime_min;
self.default_save_format =
crate::io::canonical_save_format(&s.default_save_format).to_string();
@@ -1671,7 +1673,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
// docs/dwg_constraint_compatibility_design.md: additive DWG/DXF-
// native constraint graph, alongside (not instead of) the XRecord
// above — same save-time hook.
self.tabs[i].scene.materialize_dwg_native_constraints_for_save();
self.tabs[i].scene.materialize_dwg_native_constraints_for_save(self.write_dwg_native_constraints);
}
#[cfg(not(target_arch = "wasm32"))]
@@ -2624,7 +2626,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.sync_solid_models_for_save(i);
self.tabs[i].scene.materialize_sketch_constraints_for_save();
self.tabs[i].scene.materialize_named_parameters_for_save();
self.tabs[i].scene.materialize_dwg_native_constraints_for_save();
self.tabs[i].scene.materialize_dwg_native_constraints_for_save(self.write_dwg_native_constraints);
let tab_id = self.tabs[i].id;
let bounds = crate::ui::wrap_bar::dropdown_bounds(
crate::app::view::VIEWPORT_CAPTURE_BOUNDS_ID,
+5
View File
@@ -6198,6 +6198,11 @@ impl OpenCADStudio {
}
Task::none()
}
Message::WriteDwgNativeConstraintsChanged(enabled) => {
self.write_dwg_native_constraints = enabled;
self.persist_settings_if_changed();
Task::none()
}
Message::LanguageChanged(language) => {
if self.language == language {
return Task::none();