forked from 1b-agent/opencadstudio-upstream
feat(scene): integrate standard DWG data
This commit is contained in:
1 parent
731df4a725
commit
eb23715605
38 files changed
+8376
-618
No files matched your search
@@ -18,6 +18,12 @@ pub struct MeshModel {
|
||||
pub normals: Vec<[f32; 3]>,
|
||||
/// Triangle indices into `verts` (every 3 values = one triangle).
|
||||
pub indices: Vec<u32>,
|
||||
/// Optional AcDbMaterial handle per triangle. Empty means the whole mesh
|
||||
/// uses `MeshLodSet::material`; otherwise each entry aligns with one
|
||||
/// `indices` triplet and overrides the entity material for that face.
|
||||
pub triangle_material_handles: Vec<Option<acadrust::Handle>>,
|
||||
/// Optional ACIS face colour per triangle, aligned with `indices` triplets.
|
||||
pub triangle_colors: Vec<Option<[f32; 4]>>,
|
||||
/// RGBA colour in [0, 1].
|
||||
pub color: [f32; 4],
|
||||
/// Whether this mesh is currently selected.
|
||||
@@ -94,9 +100,41 @@ pub enum CurvedGen {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StoredSilhouette {
|
||||
pub viewport_id: i64,
|
||||
pub view_direction: [f32; 3],
|
||||
pub up_vector: [f32; 3],
|
||||
pub target: [f32; 3],
|
||||
pub is_perspective: bool,
|
||||
pub edge_verts: Vec<[f32; 3]>,
|
||||
pub edge_verts_low: Vec<[f32; 3]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct MeshMetrics {
|
||||
pub vertices: usize,
|
||||
pub triangles: usize,
|
||||
pub surface_area: f64,
|
||||
pub volume: f64,
|
||||
pub centroid: [f64; 3],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MeshLodSet {
|
||||
pub lods: Vec<MeshModel>,
|
||||
/// Effective AcDbMaterial resolved from entity/layer/INSERT inheritance.
|
||||
/// Geometry remains usable when it is absent; the renderer then keeps the
|
||||
/// per-mesh entity colour.
|
||||
pub material: Option<super::material_model::MeshMaterial>,
|
||||
/// Face-level ACIS material overrides, resolved from each LOD's
|
||||
/// `triangle_material_handles`. Only handles actually referenced by the
|
||||
/// tessellation are retained.
|
||||
pub face_materials:
|
||||
rustc_hash::FxHashMap<acadrust::Handle, super::material_model::MeshMaterial>,
|
||||
/// Effective AcDbVisualStyle override resolved from the entity's full,
|
||||
/// face and edge style handles.
|
||||
pub visual_style: Option<super::visual_style_model::MeshVisualStyle>,
|
||||
/// True only when every source face produced triangles. False keeps
|
||||
/// downstream solid-edit code from treating a display-only partial shell
|
||||
/// as a closed, valid solid.
|
||||
@@ -111,6 +149,14 @@ pub struct MeshLodSet {
|
||||
/// Curved-face generators for per-frame silhouette (DISPSILH). Empty for a
|
||||
/// solid with no curved faces, or when silhouettes aren't wanted.
|
||||
pub curved_gens: Vec<CurvedGen>,
|
||||
/// View-specific silhouette caches stored in COMMON_3DSOLID. They are used
|
||||
/// when the decoded surface family cannot provide a live analytic
|
||||
/// silhouette for the current view.
|
||||
pub stored_silhouettes: Vec<StoredSilhouette>,
|
||||
/// Geometry measurements calculated once from the highest available LOD.
|
||||
/// Properties can read these without re-parsing or re-tessellating ACIS on
|
||||
/// the UI thread.
|
||||
pub metrics: MeshMetrics,
|
||||
/// World XY AABB `[min_x, min_y, max_x, max_y]` of the mesh — used
|
||||
/// by the per-frame LOD selector to compute the projected pixel
|
||||
/// diagonal.
|
||||
@@ -144,16 +190,93 @@ pub fn compute_mesh_aabb(lods: &[MeshModel]) -> ([f32; 4], [f32; 2]) {
|
||||
([min_x, min_y, max_x, max_y], [min_z, max_z])
|
||||
}
|
||||
|
||||
fn compute_mesh_metrics(lods: &[MeshModel]) -> MeshMetrics {
|
||||
let Some(mesh) = lods.iter().find(|mesh| !mesh.indices.is_empty()) else {
|
||||
return MeshMetrics::default();
|
||||
};
|
||||
let point = |index: u32| {
|
||||
let index = index as usize;
|
||||
let high = mesh.verts.get(index).copied().unwrap_or([0.0; 3]);
|
||||
let low = mesh.verts_low.get(index).copied().unwrap_or([0.0; 3]);
|
||||
[
|
||||
high[0] as f64 + low[0] as f64,
|
||||
high[1] as f64 + low[1] as f64,
|
||||
high[2] as f64 + low[2] as f64,
|
||||
]
|
||||
};
|
||||
let mut area = 0.0;
|
||||
let mut area_centroid_numerator = [0.0; 3];
|
||||
let mut signed_volume = 0.0;
|
||||
let mut centroid_numerator = [0.0; 3];
|
||||
for triangle in mesh.indices.chunks_exact(3) {
|
||||
let a = point(triangle[0]);
|
||||
let b = point(triangle[1]);
|
||||
let c = point(triangle[2]);
|
||||
let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
||||
let ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
||||
let cross = [
|
||||
ab[1] * ac[2] - ab[2] * ac[1],
|
||||
ab[2] * ac[0] - ab[0] * ac[2],
|
||||
ab[0] * ac[1] - ab[1] * ac[0],
|
||||
];
|
||||
let triangle_area = 0.5
|
||||
* (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2])
|
||||
.sqrt();
|
||||
area += triangle_area;
|
||||
for axis in 0..3 {
|
||||
area_centroid_numerator[axis] +=
|
||||
triangle_area * (a[axis] + b[axis] + c[axis]) / 3.0;
|
||||
}
|
||||
let tetra = (
|
||||
a[0] * (b[1] * c[2] - b[2] * c[1])
|
||||
- a[1] * (b[0] * c[2] - b[2] * c[0])
|
||||
+ a[2] * (b[0] * c[1] - b[1] * c[0])
|
||||
) / 6.0;
|
||||
signed_volume += tetra;
|
||||
for axis in 0..3 {
|
||||
centroid_numerator[axis] += tetra * (a[axis] + b[axis] + c[axis]) / 4.0;
|
||||
}
|
||||
}
|
||||
let centroid = if signed_volume.abs() > 1e-18 {
|
||||
[
|
||||
centroid_numerator[0] / signed_volume,
|
||||
centroid_numerator[1] / signed_volume,
|
||||
centroid_numerator[2] / signed_volume,
|
||||
]
|
||||
} else if area > 1e-18 {
|
||||
[
|
||||
area_centroid_numerator[0] / area,
|
||||
area_centroid_numerator[1] / area,
|
||||
area_centroid_numerator[2] / area,
|
||||
]
|
||||
} else {
|
||||
[0.0; 3]
|
||||
};
|
||||
MeshMetrics {
|
||||
vertices: mesh.verts.len(),
|
||||
triangles: mesh.indices.len() / 3,
|
||||
surface_area: area,
|
||||
volume: signed_volume.abs(),
|
||||
centroid,
|
||||
}
|
||||
}
|
||||
|
||||
impl MeshLodSet {
|
||||
/// Build a set from its LODs, computing the 3D AABB.
|
||||
pub fn from_lods(lods: Vec<MeshModel>) -> Self {
|
||||
let (world_aabb, z_aabb) = compute_mesh_aabb(&lods);
|
||||
let metrics = compute_mesh_metrics(&lods);
|
||||
Self {
|
||||
lods,
|
||||
material: None,
|
||||
face_materials: rustc_hash::FxHashMap::default(),
|
||||
visual_style: None,
|
||||
complete: true,
|
||||
edge_verts: Vec::new(),
|
||||
edge_verts_low: Vec::new(),
|
||||
curved_gens: Vec::new(),
|
||||
stored_silhouettes: Vec::new(),
|
||||
metrics,
|
||||
world_aabb,
|
||||
z_aabb,
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user