forked from 1b-agent/opencadstudio-upstream
Point clouds: drawn from their scans, placed, cropped and attached as the reference does
Scans (.rcs) and projects (.rcp) are read and their points drawn as screen-sized dots, coloured by the cloud's stylization. The cloud's placement carries its scale and rotation; its extents and crops stay in the scan's coordinates. A missing scan shows the extents with the saved path. -POINTCLOUDATTACH / POINTCLOUDATTACH, POINTCLOUDCROP and the POINTCLOUD* settings follow the reference's prompts and messages, the Properties list is the reference's, and a locked cloud is left alone by edits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
07f25f4bca
commit
e9c4e501db
58 files changed
+2711
-237
No files matched your search
+106
-7
@@ -2186,6 +2186,11 @@ pub struct Scene {
|
||||
frozen_hatch_cache: RefCell<HashMap<(Handle, String, u64), (u64, u64, Arc<Vec<HatchModel>>)>>,
|
||||
frozen_wipeout_cache: RefCell<HashMap<(Handle, String, u64), (u64, Arc<Vec<HatchModel>>)>>,
|
||||
frozen_image_cache: RefCell<HashMap<(Handle, u64), (u64, Arc<Vec<ImageModel>>)>>,
|
||||
/// Point clouds shown by the model content, keyed by target block and
|
||||
/// frozen-layer signature, per geometry epoch.
|
||||
point_cloud_cache: RefCell<
|
||||
HashMap<(Handle, u64), (u64, Arc<crate::scene::model::point_cloud::PointCloudSet>)>,
|
||||
>,
|
||||
frozen_mesh_cache: RefCell<HashMap<(Handle, String, u64), (u64, Arc<Vec<MeshLodSet>>)>>,
|
||||
/// Viewports that carry layer color/alpha/linetype/lineweight overrides.
|
||||
/// Cached per geometry epoch so ordinary viewports can share render data.
|
||||
@@ -2648,6 +2653,7 @@ impl Scene {
|
||||
frozen_hatch_cache: RefCell::new(HashMap::default()),
|
||||
frozen_wipeout_cache: RefCell::new(HashMap::default()),
|
||||
frozen_image_cache: RefCell::new(HashMap::default()),
|
||||
point_cloud_cache: RefCell::new(HashMap::default()),
|
||||
frozen_mesh_cache: RefCell::new(HashMap::default()),
|
||||
viewport_style_override_cache: RefCell::new(None),
|
||||
insert_hatch_cache: RefCell::new(None),
|
||||
@@ -8322,6 +8328,85 @@ impl Scene {
|
||||
arc
|
||||
}
|
||||
|
||||
/// Point clouds of the model content, with a content viewport's frozen
|
||||
/// layers removed. The paper sheet shows none. The set is rebuilt per
|
||||
/// geometry epoch; unchanged clouds keep their placed points (and GPU
|
||||
/// buffers) by key.
|
||||
pub(super) fn point_clouds_for_viewport(
|
||||
&self,
|
||||
frozen: &HashSet<Handle>,
|
||||
paper_sheet: bool,
|
||||
) -> Arc<crate::scene::model::point_cloud::PointCloudSet> {
|
||||
use crate::scene::model::point_cloud;
|
||||
static EMPTY: std::sync::OnceLock<Arc<point_cloud::PointCloudSet>> =
|
||||
std::sync::OnceLock::new();
|
||||
let empty = || Arc::clone(EMPTY.get_or_init(Default::default));
|
||||
if paper_sheet {
|
||||
return empty();
|
||||
}
|
||||
let target_block = self.content_render_block_handle();
|
||||
let key = (target_block, Self::frozen_layers_sig(frozen));
|
||||
if let Some((epoch, arc)) = self.point_cloud_cache.borrow().get(&key) {
|
||||
if *epoch == self.geometry_epoch {
|
||||
return Arc::clone(arc);
|
||||
}
|
||||
}
|
||||
let arc = if point_cloud::any_definition(&self.document) {
|
||||
let depths = rustc_hash::FxHashMap::default();
|
||||
let graph = render_graph::RenderSceneGraph::new(
|
||||
&self.document,
|
||||
(!frozen.is_empty()).then_some(frozen),
|
||||
None,
|
||||
true,
|
||||
&depths,
|
||||
);
|
||||
let mut clouds = Vec::new();
|
||||
graph.walk_root(
|
||||
self.render_scene_root(target_block),
|
||||
|entity, context| {
|
||||
context.is_instanced() || !self.entity_temporarily_hidden(entity.common().handle)
|
||||
},
|
||||
|entity, context| {
|
||||
let EntityType::Extended(extended) = entity else {
|
||||
return;
|
||||
};
|
||||
let codec::entities::ExtendedEntityData::PointCloudEx(data) = &extended.data
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let transform = context.is_instanced().then_some(&context.transform);
|
||||
// Object Color stylization draws the cloud in its own colour.
|
||||
let common = entity.common();
|
||||
let color = if matches!(common.color, codec::types::Color::ByLayer) {
|
||||
self.document
|
||||
.layers
|
||||
.get(&common.layer)
|
||||
.map(|layer| layer.color.clone())
|
||||
.unwrap_or(common.color.clone())
|
||||
} else {
|
||||
common.color.clone()
|
||||
};
|
||||
let object_color = color.rgb().map_or([255; 3], |(r, g, b)| [r, g, b]);
|
||||
clouds.extend(point_cloud::placed(&self.document, data, object_color, transform));
|
||||
},
|
||||
);
|
||||
if clouds.is_empty() {
|
||||
empty()
|
||||
} else {
|
||||
Arc::new(point_cloud::PointCloudSet {
|
||||
point_size: point_cloud::point_size(&self.document),
|
||||
clouds,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
empty()
|
||||
};
|
||||
self.point_cloud_cache
|
||||
.borrow_mut()
|
||||
.insert(key, (self.geometry_epoch, Arc::clone(&arc)));
|
||||
arc
|
||||
}
|
||||
|
||||
/// Image / OLE models for a content viewport, with its frozen layers removed.
|
||||
pub(super) fn images_for_viewport(
|
||||
&self,
|
||||
@@ -8392,14 +8477,19 @@ impl Scene {
|
||||
arc
|
||||
}
|
||||
|
||||
/// True when `handle`'s entity sits on a locked layer. Locked objects stay
|
||||
/// visible, snappable and selectable, but mutation paths must skip them.
|
||||
/// True when `handle`'s entity sits on a locked layer, or is a point cloud
|
||||
/// locked on its own. Locked objects stay visible, snappable and
|
||||
/// selectable, but mutation paths must skip them.
|
||||
pub fn is_layer_locked(&self, handle: Handle) -> bool {
|
||||
self.document
|
||||
.get_entity(handle)
|
||||
.map(|e| e.common().layer.clone())
|
||||
.and_then(|name| self.document.layers.get(&name).map(|l| l.is_locked()))
|
||||
.unwrap_or(false)
|
||||
let Some(entity) = self.document.get_entity(handle) else {
|
||||
return false;
|
||||
};
|
||||
is_locked_point_cloud(entity)
|
||||
|| self
|
||||
.document
|
||||
.layers
|
||||
.get(&entity.common().layer)
|
||||
.is_some_and(|l| l.is_locked())
|
||||
}
|
||||
|
||||
/// The name of the locked layer `handle` sits on, if any (for messages).
|
||||
@@ -13817,3 +13907,12 @@ mod update_entities_batch_tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A point cloud whose Locked property is set: edits leave it alone.
|
||||
pub(crate) fn is_locked_point_cloud(entity: &EntityType) -> bool {
|
||||
matches!(
|
||||
entity,
|
||||
EntityType::Extended(extended)
|
||||
if matches!(&extended.data, codec::entities::ExtendedEntityData::PointCloudEx(data) if data.locked)
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user