forked from 1b-agent/opencadstudio-upstream
Merge origin/main into plugin/host-model-api
Conflicts were additive: main's AddLayer/ModifyLayer (LayerConfig, OptHandle) alongside this branch's v7 system-variable, transaction, selection and solid operations. Main's variants keep their positions in the IPC enums; the v7 additions follow them. src/io/mod.rs takes main's reworded Shape-rotation note. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
commit
6b8056cfeb
28 files changed
+1425
-97
No files matched your search
@@ -1443,6 +1443,17 @@ impl Scene {
|
||||
if self.is_layer_locked(handle) {
|
||||
return;
|
||||
}
|
||||
// An attribute grip sits on the displayed (annotation-scaled)
|
||||
// attribute; the stored one is unscaled.
|
||||
let apply = match self.document.get_entity(handle) {
|
||||
Some(EntityType::Insert(insert)) => crate::entities::insert::unscale_attribute_grip(
|
||||
insert,
|
||||
self.annotation_scale,
|
||||
grip_id,
|
||||
apply,
|
||||
),
|
||||
_ => apply,
|
||||
};
|
||||
if self.apply_solid_history_grip(handle, grip_id, apply.clone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
+29
-6
@@ -175,7 +175,23 @@ impl Scene {
|
||||
let ObjectType::Dictionary(d) = self.document.objects.get(&dh)? else {
|
||||
return None;
|
||||
};
|
||||
d.entries.iter().find(|(k, _)| k == name).map(|(_, h)| *h)
|
||||
d.entries
|
||||
.iter()
|
||||
.find(|(k, _)| k.eq_ignore_ascii_case(name))
|
||||
.map(|(_, h)| *h)
|
||||
}
|
||||
|
||||
/// The dictionary's own spelling of `name` (page-setup names compare
|
||||
/// case-insensitively, like every named-object dictionary key).
|
||||
fn page_setup_key(&self, name: &str) -> Option<String> {
|
||||
let dh = self.plotsettings_dict_handle()?;
|
||||
let ObjectType::Dictionary(d) = self.document.objects.get(&dh)? else {
|
||||
return None;
|
||||
};
|
||||
d.entries
|
||||
.iter()
|
||||
.find(|(k, _)| k.eq_ignore_ascii_case(name))
|
||||
.map(|(k, _)| k.clone())
|
||||
}
|
||||
|
||||
/// Create or update the named page setup from `ps` (its `page_name` and
|
||||
@@ -183,7 +199,9 @@ impl Scene {
|
||||
/// are inserted and registered in the dictionary.
|
||||
pub fn page_setup_save(&mut self, name: &str, mut ps: PlotSettings) {
|
||||
let dict_handle = self.ensure_plotsettings_dict();
|
||||
ps.page_name = name.to_string();
|
||||
// Replacing keeps the entry's stored spelling so the dictionary key
|
||||
// and the object's page_name stay one name.
|
||||
ps.page_name = self.page_setup_key(name).unwrap_or_else(|| name.to_string());
|
||||
ps.owner = dict_handle;
|
||||
if let Some(h) = self.page_setup_handle(name) {
|
||||
ps.handle = h;
|
||||
@@ -206,8 +224,12 @@ impl Scene {
|
||||
let handle = if let Some(ObjectType::Dictionary(d)) =
|
||||
self.document.objects.get_mut(&dict_handle)
|
||||
{
|
||||
let h = d.entries.iter().find(|(k, _)| k == name).map(|(_, h)| *h);
|
||||
d.entries.retain(|(k, _)| k != name);
|
||||
let h = d
|
||||
.entries
|
||||
.iter()
|
||||
.find(|(k, _)| k.eq_ignore_ascii_case(name))
|
||||
.map(|(_, h)| *h);
|
||||
d.entries.retain(|(k, _)| !k.eq_ignore_ascii_case(name));
|
||||
h
|
||||
} else {
|
||||
None
|
||||
@@ -223,7 +245,8 @@ impl Scene {
|
||||
if old == new || new.trim().is_empty() {
|
||||
return;
|
||||
}
|
||||
if self.page_setup_handle(new).is_some() {
|
||||
// A different spelling of the same name is a rename, not a collision.
|
||||
if !old.eq_ignore_ascii_case(new) && self.page_setup_handle(new).is_some() {
|
||||
return; // name collision
|
||||
}
|
||||
let Some(dict_handle) = self.plotsettings_dict_handle() else {
|
||||
@@ -231,7 +254,7 @@ impl Scene {
|
||||
};
|
||||
let mut renamed = None;
|
||||
if let Some(ObjectType::Dictionary(d)) = self.document.objects.get_mut(&dict_handle) {
|
||||
if let Some(e) = d.entries.iter_mut().find(|(k, _)| k == old) {
|
||||
if let Some(e) = d.entries.iter_mut().find(|(k, _)| k.eq_ignore_ascii_case(old)) {
|
||||
e.0 = new.to_string();
|
||||
renamed = Some(e.1);
|
||||
}
|
||||
|
||||
@@ -244,6 +244,9 @@ pub(crate) fn set_polyline_vertex(
|
||||
x: f64,
|
||||
y: f64,
|
||||
) -> bool {
|
||||
let Some(index) = polyline_vertex_index(entity, index) else {
|
||||
return false;
|
||||
};
|
||||
match entity {
|
||||
acadrust::EntityType::LwPolyline(polyline) => polyline
|
||||
.vertices
|
||||
@@ -800,9 +803,27 @@ pub(crate) fn resolve_point(entity: &acadrust::EntityType, marker: i32) -> Optio
|
||||
if marker < 0 {
|
||||
return None;
|
||||
}
|
||||
super::dimension_assoc::source_points(entity)
|
||||
.get(marker as usize)
|
||||
.copied()
|
||||
let points = super::dimension_assoc::source_points(entity);
|
||||
// The closing segment of a closed polyline runs back to vertex 0, so its
|
||||
// end marker (one past the last vertex) names that vertex — the same wrap
|
||||
// the solver's `line_segment` applies.
|
||||
let index = match polyline_vertex_index(entity, marker as usize) {
|
||||
Some(index) => index,
|
||||
None => marker as usize,
|
||||
};
|
||||
points.get(index).copied()
|
||||
}
|
||||
|
||||
/// `marker` as a vertex index of a polyline, wrapping the closing segment's
|
||||
/// end (one past the last vertex) onto vertex 0 when the polyline is closed.
|
||||
/// `None` for anything that is not a 2D polyline.
|
||||
pub(crate) fn polyline_vertex_index(entity: &acadrust::EntityType, marker: usize) -> Option<usize> {
|
||||
let (count, closed) = match entity {
|
||||
acadrust::EntityType::LwPolyline(polyline) => (polyline.vertices.len(), polyline.is_closed),
|
||||
acadrust::EntityType::Polyline2D(polyline) => (polyline.vertices.len(), polyline.is_closed()),
|
||||
_ => return None,
|
||||
};
|
||||
Some(if closed && marker == count && count > 0 { 0 } else { marker })
|
||||
}
|
||||
|
||||
/// Below this squared distance (1e-6 world units), two points count as
|
||||
|
||||
@@ -87,8 +87,16 @@ impl EntityGeom {
|
||||
(EntityGeom::Line(l), 0) => Some(l.p1),
|
||||
(EntityGeom::Line(l), 1) => Some(l.p2),
|
||||
(EntityGeom::Ray(l), 0) => Some(l.p1),
|
||||
(EntityGeom::Polyline { points, .. }, marker) if marker >= 0 => {
|
||||
points.get(marker as usize).copied()
|
||||
(EntityGeom::Polyline { points, closed, .. }, marker) if marker >= 0 => {
|
||||
// The closing segment's end marker (one past the last vertex)
|
||||
// is vertex 0 on a closed polyline, as in `line_segment`.
|
||||
let index = marker as usize;
|
||||
let index = if *closed && index == points.len() && !points.is_empty() {
|
||||
0
|
||||
} else {
|
||||
index
|
||||
};
|
||||
points.get(index).copied()
|
||||
}
|
||||
(EntityGeom::Circle(c), -3) => Some(c.center),
|
||||
(EntityGeom::Arc(a), 0) => Some(a.start),
|
||||
|
||||
Reference in new issue
Block a user