forked from 1b-agent/opencadstudio-upstream
fix: preserve web builds and leader selection order
This commit is contained in:
1 parent
6d5763bb70
commit
cba2680be0
5 files changed
+38
-68
No files matched your search
@@ -106,14 +106,6 @@ impl OpenCADStudio {
|
|||||||
&handles,
|
&handles,
|
||||||
);
|
);
|
||||||
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
||||||
// Copy to system clipboard as JSON for web/cross-platform support
|
|
||||||
if let Ok(clipboard_data) = serde_json::to_string(&self.clipboard) {
|
|
||||||
return Some(iced::clipboard::write(format!(
|
|
||||||
"OCS_CLIPBOARD_JSON\n{}\n{}",
|
|
||||||
serde_json::json!([base.x, base.y, base.z]).to_string(),
|
|
||||||
clipboard_data
|
|
||||||
)).discard());
|
|
||||||
}
|
|
||||||
self.command_line.push_info(crate::tf!(
|
self.command_line.push_info(crate::tf!(
|
||||||
"{} object(s) copied to clipboard.",
|
"{} object(s) copied to clipboard.",
|
||||||
count
|
count
|
||||||
@@ -159,14 +151,6 @@ impl OpenCADStudio {
|
|||||||
if coords.len() == 3 && !handles.is_empty() {
|
if coords.len() == 3 && !handles.is_empty() {
|
||||||
let base = glam::DVec3::new(coords[0], coords[1], coords[2]);
|
let base = glam::DVec3::new(coords[0], coords[1], coords[2]);
|
||||||
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
||||||
// Copy to system clipboard as JSON for web/cross-platform support
|
|
||||||
if let Ok(clipboard_data) = serde_json::to_string(&self.clipboard) {
|
|
||||||
let _ = iced::clipboard::write(format!(
|
|
||||||
"OCS_CLIPBOARD_JSON\n{}\n{}",
|
|
||||||
serde_json::json!([base.x, base.y, base.z]).to_string(),
|
|
||||||
clipboard_data
|
|
||||||
));
|
|
||||||
}
|
|
||||||
self.command_line.push_info(crate::tf!(
|
self.command_line.push_info(crate::tf!(
|
||||||
"{} object(s) copied to clipboard (base {:.3},{:.3}).",
|
"{} object(s) copied to clipboard (base {:.3},{:.3}).",
|
||||||
count,
|
count,
|
||||||
@@ -195,14 +179,6 @@ impl OpenCADStudio {
|
|||||||
&handles,
|
&handles,
|
||||||
);
|
);
|
||||||
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
let count = self.copy_entities_to_clipboard(i, &handles, base);
|
||||||
// Copy to system clipboard as JSON for web/cross-platform support
|
|
||||||
if let Ok(clipboard_data) = serde_json::to_string(&self.clipboard) {
|
|
||||||
let _ = iced::clipboard::write(format!(
|
|
||||||
"OCS_CLIPBOARD_JSON\n{}\n{}",
|
|
||||||
serde_json::json!([base.x, base.y, base.z]).to_string(),
|
|
||||||
clipboard_data
|
|
||||||
));
|
|
||||||
}
|
|
||||||
self.push_undo_snapshot(i, "CUTCLIP");
|
self.push_undo_snapshot(i, "CUTCLIP");
|
||||||
self.tabs[i].scene.erase_entities(&handles);
|
self.tabs[i].scene.erase_entities(&handles);
|
||||||
self.tabs[i].scene.deselect_all();
|
self.tabs[i].scene.deselect_all();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ impl OpenCADStudio {
|
|||||||
// A 186 468-entity selection spends ~112 ms in here. Split it into the
|
// A 186 468-entity selection spends ~112 ms in here. Split it into the
|
||||||
// three phases that can own that: resolving the selected handles,
|
// three phases that can own that: resolving the selected handles,
|
||||||
// building the panel, and syncing the ribbon.
|
// building the panel, and syncing the ribbon.
|
||||||
let t_all = crate::perf::enabled().then(std::time::Instant::now);
|
let t_all = crate::perf::enabled().then(iced::time::Instant::now);
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
if !crate::entities::object_data::cache_is_prepared(
|
if !crate::entities::object_data::cache_is_prepared(
|
||||||
&self.tabs[i].scene.object_data_cache,
|
&self.tabs[i].scene.object_data_cache,
|
||||||
@@ -112,7 +112,7 @@ impl OpenCADStudio {
|
|||||||
// Everything before this is the prelude: the object-data cache, the
|
// Everything before this is the prelude: the object-data cache, the
|
||||||
// unit context, the layer and linetype lists.
|
// unit context, the layer and linetype lists.
|
||||||
let m_prelude = t_all.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
let m_prelude = t_all.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
||||||
let t_handles = crate::perf::enabled().then(std::time::Instant::now);
|
let t_handles = crate::perf::enabled().then(iced::time::Instant::now);
|
||||||
// `selected_entities` resolves every handle to an entity and builds a
|
// `selected_entities` resolves every handle to an entity and builds a
|
||||||
// vector of pairs; only the handles are wanted here, but the resolution
|
// vector of pairs; only the handles are wanted here, but the resolution
|
||||||
// is what decides membership — a handle whose entity is gone is not in
|
// is what decides membership — a handle whose entity is gone is not in
|
||||||
@@ -2196,7 +2196,7 @@ impl OpenCADStudio {
|
|||||||
// the active group, moving into the working plane, and
|
// the active group, moving into the working plane, and
|
||||||
// aggregating into "varies" rows. `properties-detail`
|
// aggregating into "varies" rows. `properties-detail`
|
||||||
// reports this whole arm as `rest`; this splits it.
|
// reports this whole arm as `rest`; this splits it.
|
||||||
let t_arm = crate::perf::enabled().then(std::time::Instant::now);
|
let t_arm = crate::perf::enabled().then(iced::time::Instant::now);
|
||||||
let groups = build_selection_groups(&selected);
|
let groups = build_selection_groups(&selected);
|
||||||
let t_groups = t_arm.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
let t_groups = t_arm.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
||||||
let active_group = selected_group
|
let active_group = selected_group
|
||||||
@@ -2372,7 +2372,7 @@ filter={:.1} local={:.1} aggregate={:.1} entities={}",
|
|||||||
self.tabs[i].properties = new_panel;
|
self.tabs[i].properties = new_panel;
|
||||||
self.refresh_selected_grips();
|
self.refresh_selected_grips();
|
||||||
let m_panel = t_all.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
let m_panel = t_all.map(|t| t.elapsed().as_secs_f64() * 1000.0);
|
||||||
let t_ribbon = crate::perf::enabled().then(std::time::Instant::now);
|
let t_ribbon = crate::perf::enabled().then(iced::time::Instant::now);
|
||||||
self.sync_ribbon_from_selection();
|
self.sync_ribbon_from_selection();
|
||||||
if let Some(t) = t_all {
|
if let Some(t) = t_all {
|
||||||
let ribbon_ms = t_ribbon.map_or(0.0, |r| r.elapsed().as_secs_f64() * 1000.0);
|
let ribbon_ms = t_ribbon.map_or(0.0, |r| r.elapsed().as_secs_f64() * 1000.0);
|
||||||
|
|||||||
@@ -75,3 +75,11 @@ pub mod prelude {
|
|||||||
|
|
||||||
impl<I: Iterator> IterParExt for I {}
|
impl<I: Iterator> IterParExt for I {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub use rayon::join;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub fn join<A, B>(a: impl FnOnce() -> A, b: impl FnOnce() -> B) -> (A, B) {
|
||||||
|
(a(), b())
|
||||||
|
}
|
||||||
@@ -914,17 +914,17 @@ impl InteractionIndex {
|
|||||||
let (
|
let (
|
||||||
((segment_entries, snap_point_entries), (key_vertex_entries, key_segment_entries)),
|
((segment_entries, snap_point_entries), (key_vertex_entries, key_segment_entries)),
|
||||||
((fill_triangle_entries, pick_triangle_entries), glyph_entries),
|
((fill_triangle_entries, pick_triangle_entries), glyph_entries),
|
||||||
) = rayon::join(
|
) = crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| flatten_entry_parts(segment_parts),
|
|| flatten_entry_parts(segment_parts),
|
||||||
|| flatten_entry_parts(snap_point_parts),
|
|| flatten_entry_parts(snap_point_parts),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| flatten_entry_parts(key_vertex_parts),
|
|| flatten_entry_parts(key_vertex_parts),
|
||||||
|| flatten_entry_parts(key_segment_parts),
|
|| flatten_entry_parts(key_segment_parts),
|
||||||
)
|
)
|
||||||
@@ -932,7 +932,7 @@ impl InteractionIndex {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
let (fill, pick) = rayon::join(
|
let (fill, pick) = crate::par::join(
|
||||||
|| flatten_entry_parts(fill_triangle_parts),
|
|| flatten_entry_parts(fill_triangle_parts),
|
||||||
|| flatten_entry_parts(pick_triangle_parts),
|
|| flatten_entry_parts(pick_triangle_parts),
|
||||||
);
|
);
|
||||||
@@ -966,17 +966,17 @@ impl InteractionIndex {
|
|||||||
let (
|
let (
|
||||||
((wires, segments), (snap_points, key_vertices)),
|
((wires, segments), (snap_points, key_vertices)),
|
||||||
((key_segments, fill_triangles), (pick_triangles, glyphs)),
|
((key_segments, fill_triangles), (pick_triangles, glyphs)),
|
||||||
) = rayon::join(
|
) = crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| SpatialSet::build(wire_entries),
|
|| SpatialSet::build(wire_entries),
|
||||||
|| SpatialSet::build(segment_entries),
|
|| SpatialSet::build(segment_entries),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| SpatialSet::build(snap_point_entries),
|
|| SpatialSet::build(snap_point_entries),
|
||||||
|| SpatialSet::build(key_vertex_entries),
|
|| SpatialSet::build(key_vertex_entries),
|
||||||
)
|
)
|
||||||
@@ -984,15 +984,15 @@ impl InteractionIndex {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| SpatialSet::build(key_segment_entries),
|
|| SpatialSet::build(key_segment_entries),
|
||||||
|| SpatialSet::build(fill_triangle_entries),
|
|| SpatialSet::build(fill_triangle_entries),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| SpatialSet::build(pick_triangle_entries),
|
|| SpatialSet::build(pick_triangle_entries),
|
||||||
|| SpatialSet::build(glyph_entries),
|
|| SpatialSet::build(glyph_entries),
|
||||||
)
|
)
|
||||||
@@ -1054,12 +1054,12 @@ impl InteractionIndex {
|
|||||||
/// thread. Perspective/orbit hover must never pay this one-time cost.
|
/// thread. Perspective/orbit hover must never pay this one-time cost.
|
||||||
pub fn prepare_screen(&self) {
|
pub fn prepare_screen(&self) {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| rayon::join(|| self.wires.prepare_screen(), || self.segments.prepare_screen()),
|
|| crate::par::join(|| self.wires.prepare_screen(), || self.segments.prepare_screen()),
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| self.snap_points.prepare_screen(),
|
|| self.snap_points.prepare_screen(),
|
||||||
|| self.key_vertices.prepare_screen(),
|
|| self.key_vertices.prepare_screen(),
|
||||||
)
|
)
|
||||||
@@ -1067,15 +1067,15 @@ impl InteractionIndex {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| self.key_segments.prepare_screen(),
|
|| self.key_segments.prepare_screen(),
|
||||||
|| self.fill_triangles.prepare_screen(),
|
|| self.fill_triangles.prepare_screen(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| self.pick_triangles.prepare_screen(),
|
|| self.pick_triangles.prepare_screen(),
|
||||||
|| self.glyphs.prepare_screen(),
|
|| self.glyphs.prepare_screen(),
|
||||||
)
|
)
|
||||||
@@ -1426,9 +1426,9 @@ impl InteractionIndex {
|
|||||||
// sum. Each closure still calls the same query, so the results are
|
// sum. Each closure still calls the same query, so the results are
|
||||||
// identical to the sequential ones, order included.
|
// identical to the sequential ones, order included.
|
||||||
let ((wire_indices, segments), ((fill_triangles, pick_triangles), glyphs)) =
|
let ((wire_indices, segments), ((fill_triangles, pick_triangles), glyphs)) =
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
let mut indices = self.wires.query_xy_unordered(aabb);
|
let mut indices = self.wires.query_xy_unordered(aabb);
|
||||||
indices.extend_from_slice(&self.unbounded_wires);
|
indices.extend_from_slice(&self.unbounded_wires);
|
||||||
@@ -1440,9 +1440,9 @@ impl InteractionIndex {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| {
|
|| {
|
||||||
rayon::join(
|
crate::par::join(
|
||||||
|| self.fill_triangles.query_xy_unordered(aabb),
|
|| self.fill_triangles.query_xy_unordered(aabb),
|
||||||
|| self.pick_triangles.query_xy_unordered(aabb),
|
|| self.pick_triangles.query_xy_unordered(aabb),
|
||||||
)
|
)
|
||||||
|
|||||||
+3
-17
@@ -47,6 +47,7 @@ impl Scene {
|
|||||||
let leaders = self.leaders_by_annotation();
|
let leaders = self.leaders_by_annotation();
|
||||||
let mut expanded = Vec::with_capacity(handles.len());
|
let mut expanded = Vec::with_capacity(handles.len());
|
||||||
for &handle in handles {
|
for &handle in handles {
|
||||||
|
let start = expanded.len();
|
||||||
expanded.push(handle);
|
expanded.push(handle);
|
||||||
if let Some(EntityType::Leader(leader)) = self.document.get_entity(handle) {
|
if let Some(EntityType::Leader(leader)) = self.document.get_entity(handle) {
|
||||||
if !leader.annotation_handle.is_null() {
|
if !leader.annotation_handle.is_null() {
|
||||||
@@ -56,6 +57,7 @@ impl Scene {
|
|||||||
if let Some(pointing) = leaders.1.get(&handle) {
|
if let Some(pointing) = leaders.1.get(&handle) {
|
||||||
expanded.extend(pointing.iter().copied());
|
expanded.extend(pointing.iter().copied());
|
||||||
}
|
}
|
||||||
|
expanded[start..].sort_unstable_by_key(Handle::value);
|
||||||
}
|
}
|
||||||
expanded
|
expanded
|
||||||
}
|
}
|
||||||
@@ -106,23 +108,7 @@ impl Scene {
|
|||||||
&self,
|
&self,
|
||||||
handles: &[Handle],
|
handles: &[Handle],
|
||||||
) -> Vec<Handle> {
|
) -> Vec<Handle> {
|
||||||
let mut expanded = handles.to_vec();
|
let mut expanded = self.expanded_with_leaders(handles);
|
||||||
let leaders = self.leaders_by_annotation();
|
|
||||||
|
|
||||||
for &handle in handles {
|
|
||||||
// LEADER -> annotation.
|
|
||||||
if let Some(EntityType::Leader(leader)) = self.document.get_entity(handle) {
|
|
||||||
if !leader.annotation_handle.is_null() {
|
|
||||||
expanded.push(leader.annotation_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Annotation -> LEADER.
|
|
||||||
if let Some(pointing) = leaders.1.get(&handle) {
|
|
||||||
expanded.extend(pointing.iter().copied());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expanded.sort_unstable_by_key(|handle| handle.value());
|
expanded.sort_unstable_by_key(|handle| handle.value());
|
||||||
expanded.dedup();
|
expanded.dedup();
|
||||||
expanded
|
expanded
|
||||||
|
|||||||
Reference in new issue
Block a user