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 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-09-29 17:08:46 +03:00
1 parent 07f25f4bca
commit e9c4e501db
58 files changed
+2711 -237

No files matched your search

+36
View File
@@ -322,6 +322,21 @@ pub fn register_underlay_sources(doc: &CadDocument, base_dir: &Path) {
crate::scene::model::pdf_raster::register_source(stored, std::sync::Arc::new(bytes));
}
}
// Point cloud scans are large and read lazily: register where they are.
for object in doc.objects.values() {
let codec::objects::ObjectType::ClassObject(object) = object else {
continue;
};
let (codec::objects::ClassObjectData::PointCloudDefinitionEx(def)
| codec::objects::ClassObjectData::PointCloudDefinition(def)) = &object.data
else {
continue;
};
let stored = def.source_filename.trim();
if let Some(found) = (!stored.is_empty()).then(|| resolve_path(stored, base_dir)).flatten() {
crate::scene::model::point_cloud::register_source(stored, found);
}
}
}
/// Layer properties an override can change, as compared for the
@@ -3106,3 +3121,24 @@ mod tests {
}
}
}
/// Point cloud definitions keep the full path while the drawing is open; a
/// DWG stores it relative to the drawing (".\rcs\scan.rcs"), as the
/// reference writes it. Paths on another drive stay full.
pub fn relative_point_cloud_paths(doc: &mut CadDocument, host: &Path) {
use crate::io::xref_model::{is_relative_path, normalize_lexical, to_pathtype_result, Pathtype};
for object in doc.objects.values_mut() {
let codec::objects::ObjectType::ClassObject(object) = object else {
continue;
};
let codec::objects::ClassObjectData::PointCloudDefinitionEx(def) = &mut object.data else {
continue;
};
if def.source_filename.is_empty() || is_relative_path(&normalize_lexical(&def.source_filename)) {
continue;
}
if let Ok(relative) = to_pathtype_result(&def.source_filename, host, Pathtype::Relative) {
def.source_filename = relative.replace('/', "\\");
}
}
}