feat: Region and Body entity tessellation + render
Refactors solid3d_tess to share tessellate_sat() across Solid3D, Region (2D planar ACIS body), and Body (3D ACIS body). populate_meshes_from_document() and add_entity() now tessellate all three entity types into GPU MeshModels when ACIS SAT data is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
67b5f5e3d5
commit
5cf7a19ca8
3 changed files with 60 additions and 41 deletions
|
|
@ -279,7 +279,7 @@ Underlay (PDF/DWF/DGN)
|
||||||
| Sağ tık bağlam menüsü | ✅ |
|
| Sağ tık bağlam menüsü | ✅ |
|
||||||
| Araç çubuğu özelleştirme | ⬜ |
|
| Araç çubuğu özelleştirme | ⬜ |
|
||||||
| Tema / Renk şeması seçimi | ✅ |
|
| Tema / Renk şeması seçimi | ✅ |
|
||||||
| Klavye kısayol düzenleyici | ⬜ |
|
| Klavye kısayol düzenleyici | ✅ |
|
||||||
| Komut geçmişi gezinme (↑↓) | ✅ |
|
| Komut geçmişi gezinme (↑↓) | ✅ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -1094,11 +1094,20 @@ impl Scene {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mesh_seed = if let EntityType::Solid3D(s3d) = &entity {
|
let mesh_seed = match &entity {
|
||||||
|
EntityType::Solid3D(s3d) => {
|
||||||
let color = self.render_style(&entity).0;
|
let color = self.render_style(&entity).0;
|
||||||
solid3d_tess::tessellate_solid3d(s3d, color)
|
solid3d_tess::tessellate_solid3d(s3d, color)
|
||||||
} else {
|
}
|
||||||
None
|
EntityType::Region(r) => {
|
||||||
|
let color = self.render_style(&entity).0;
|
||||||
|
solid3d_tess::tessellate_region(r, color)
|
||||||
|
}
|
||||||
|
EntityType::Body(b) => {
|
||||||
|
let color = self.render_style(&entity).0;
|
||||||
|
solid3d_tess::tessellate_body(b, color)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auto-create an ImageDefinition object for new RasterImage entities
|
// Auto-create an ImageDefinition object for new RasterImage entities
|
||||||
|
|
@ -1605,25 +1614,30 @@ impl Scene {
|
||||||
/// `Solid3D` entity is represented in the mesh cache.
|
/// `Solid3D` entity is represented in the mesh cache.
|
||||||
pub fn populate_meshes_from_document(&mut self) {
|
pub fn populate_meshes_from_document(&mut self) {
|
||||||
self.meshes.clear();
|
self.meshes.clear();
|
||||||
let entries: Vec<(Handle, Solid3D)> = self
|
// Collect all ACIS-bearing entities: Solid3D, Region, Body.
|
||||||
|
let entries: Vec<(Handle, EntityType)> = self
|
||||||
.document
|
.document
|
||||||
.entities()
|
.entities()
|
||||||
.filter_map(|e| {
|
.filter_map(|e| match e {
|
||||||
if let EntityType::Solid3D(s) = e {
|
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) =>
|
||||||
Some((s.common.handle, s.clone()))
|
Some((e.common().handle, e.clone())),
|
||||||
} else {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
for (handle, solid) in entries {
|
for (handle, entity) in entries {
|
||||||
let color = if let Some(e) = self.document.get_entity(handle) {
|
let color = if let Some(e) = self.document.get_entity(handle) {
|
||||||
tessellate::aci_to_rgba(&e.common().color)
|
tessellate::aci_to_rgba(&e.common().color)
|
||||||
} else {
|
} else {
|
||||||
[0.7, 0.7, 0.7, 1.0]
|
[0.7, 0.7, 0.7, 1.0]
|
||||||
};
|
};
|
||||||
if let Some(model) = solid3d_tess::tessellate_solid3d(&solid, color) {
|
let model = match &entity {
|
||||||
self.meshes.insert(handle, model);
|
EntityType::Solid3D(s) => solid3d_tess::tessellate_solid3d(s, color),
|
||||||
|
EntityType::Region(r) => solid3d_tess::tessellate_region(r, color),
|
||||||
|
EntityType::Body(b) => solid3d_tess::tessellate_body(b, color),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(m) = model {
|
||||||
|
self.meshes.insert(handle, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use acadrust::entities::acis::{
|
||||||
SatPointer, SatSphereSurface, SatTorusSurface, SatVertex,
|
SatPointer, SatSphereSurface, SatTorusSurface, SatVertex,
|
||||||
};
|
};
|
||||||
use acadrust::entities::acis::types::Sense;
|
use acadrust::entities::acis::types::Sense;
|
||||||
use acadrust::entities::Solid3D;
|
use acadrust::entities::{Body, Region, Solid3D};
|
||||||
|
|
||||||
use crate::scene::mesh_model::MeshModel;
|
use crate::scene::mesh_model::MeshModel;
|
||||||
|
|
||||||
|
|
@ -30,32 +30,24 @@ const GRID_V: usize = 16;
|
||||||
|
|
||||||
// ── Public entry point ────────────────────────────────────────────────────────
|
// ── Public entry point ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// Tessellate a `Solid3D` entity into a GPU-ready `MeshModel`.
|
/// Tessellate a SAT document into mesh buffers — shared by all ACIS entities.
|
||||||
///
|
fn tessellate_sat(sat: &SatDocument, name: String, color: [f32; 4]) -> Option<MeshModel> {
|
||||||
/// Returns `None` when the entity has no parseable SAT data or produces no
|
|
||||||
/// triangles (e.g. the solid uses only unsupported surface types).
|
|
||||||
pub fn tessellate_solid3d(solid: &Solid3D, color: [f32; 4]) -> Option<MeshModel> {
|
|
||||||
let sat = solid.parse_sat()?;
|
|
||||||
|
|
||||||
let mut verts: Vec<[f32; 3]> = Vec::new();
|
let mut verts: Vec<[f32; 3]> = Vec::new();
|
||||||
let mut normals: Vec<[f32; 3]> = Vec::new();
|
let mut normals: Vec<[f32; 3]> = Vec::new();
|
||||||
let mut indices: Vec<u32> = Vec::new();
|
let mut indices: Vec<u32> = Vec::new();
|
||||||
|
|
||||||
for face in sat.faces() {
|
for face in sat.faces() {
|
||||||
let surf_ptr = face.surface();
|
let surf_ptr = face.surface();
|
||||||
let Some(surf_rec) = sat.resolve(surf_ptr) else {
|
let Some(surf_rec) = sat.resolve(surf_ptr) else { continue };
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
match surf_rec.entity_type.as_str() {
|
match surf_rec.entity_type.as_str() {
|
||||||
"plane-surface" => {
|
"plane-surface" => {
|
||||||
if let Some(plane) = SatPlaneSurface::from_record(surf_rec) {
|
if let Some(plane) = SatPlaneSurface::from_record(surf_rec) {
|
||||||
tess_plane_face(&sat, &face, &plane, &mut verts, &mut normals, &mut indices);
|
tess_plane_face(sat, &face, &plane, &mut verts, &mut normals, &mut indices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"cone-surface" => {
|
"cone-surface" => {
|
||||||
if let Some(cone) = SatConeSurface::from_record(surf_rec) {
|
if let Some(cone) = SatConeSurface::from_record(surf_rec) {
|
||||||
tess_cone_face(&sat, &face, &cone, &mut verts, &mut normals, &mut indices);
|
tess_cone_face(sat, &face, &cone, &mut verts, &mut normals, &mut indices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"sphere-surface" => {
|
"sphere-surface" => {
|
||||||
|
|
@ -71,19 +63,32 @@ pub fn tessellate_solid3d(solid: &Solid3D, color: [f32; 4]) -> Option<MeshModel>
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if indices.is_empty() { return None; }
|
||||||
if indices.is_empty() {
|
Some(MeshModel { name, verts, normals, indices, color, selected: false })
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(MeshModel {
|
/// Tessellate a `Region` entity (2D planar ACIS body) into a `MeshModel`.
|
||||||
name: solid.common.handle.value().to_string(),
|
pub fn tessellate_region(region: &Region, color: [f32; 4]) -> Option<MeshModel> {
|
||||||
verts,
|
let sat = region.parse_sat()?;
|
||||||
normals,
|
let name = region.common.handle.value().to_string();
|
||||||
indices,
|
tessellate_sat(&sat, name, color)
|
||||||
color,
|
}
|
||||||
selected: false,
|
|
||||||
})
|
/// Tessellate a `Body` entity (3D ACIS body) into a `MeshModel`.
|
||||||
|
pub fn tessellate_body(body: &Body, color: [f32; 4]) -> Option<MeshModel> {
|
||||||
|
let sat = body.parse_sat()?;
|
||||||
|
let name = body.common.handle.value().to_string();
|
||||||
|
tessellate_sat(&sat, name, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tessellate a `Solid3D` entity into a GPU-ready `MeshModel`.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the entity has no parseable SAT data or produces no
|
||||||
|
/// triangles (e.g. the solid uses only unsupported surface types).
|
||||||
|
pub fn tessellate_solid3d(solid: &Solid3D, color: [f32; 4]) -> Option<MeshModel> {
|
||||||
|
let sat = solid.parse_sat()?;
|
||||||
|
let name = solid.common.handle.value().to_string();
|
||||||
|
tessellate_sat(&sat, name, color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Topology helpers ──────────────────────────────────────────────────────────
|
// ── Topology helpers ──────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue