feat: node graph overlay; move to opencadcodec/opencadkernel/opencadgraph

The codec and kernel repositories and crates are renamed opencadcodec and
opencadkernel. Inside OCS they are depended on under short keys, so code
reads `codec::`, `kernel::` and the new `graph::` (opencadgraph, the node
graph engine). File-format and protocol spellings stay as they were: the
ACIS product id `acadrust`, the ACADRUST_* switches and the plugin
version keys `acadrust_version` / `acadrust_source`.

A button left of MCP on the command line opens a translucent node graph
over the viewport, with a palette of object, input, math, logic, list,
text and geometry nodes added by click or drag. An object node owns
drawing entities and its rows are the Properties panel's own rows for
them: the single-object page is extracted from refresh_properties as
entity_property_sections, values use the control protocol's
property_json, and writes go through set_property_value with a property
target override, so the panel, MCP and the graph share one read/write
path. A list reaching an object row makes one entity per element. Each
graph action is one undo step; the canvas pans and zooms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-09-25 07:34:23 +03:00
1 parent 56c04408d6
commit f537aff75c
430 files changed
+9925 -8540

No files matched your search

+1 -1
View File
@@ -337,7 +337,7 @@ pub fn render_emf(data: &[u8]) -> Option<(Vec<u8>, u32, u32)> {
}
/// Rasterize a WMF picture, placeable or standard. WMFC-wrapped enhanced
/// metafiles never reach here — acadrust's presentation extraction already
/// metafiles never reach here — opencadcodec's presentation extraction already
/// reassembles those to EMF.
pub fn render_wmf(data: &[u8]) -> Option<(Vec<u8>, u32, u32)> {
wmf::render(data)
+7 -7
View File
@@ -3,7 +3,7 @@
use std::sync::Arc;
use cadkernel::geom2d::{
use kernel::geom2d::{
inside_spans, Curve as KernelCurve, Line as KernelLine, Tolerance, XLine as KernelXLine,
};
@@ -244,11 +244,11 @@ pub struct HatchModel {
/// Per-ring DXF role, aligned with the NaN-separated boundary paths.
pub boundary_exterior: Option<Arc<Vec<bool>>>,
/// Source entity handles for each boundary ring.
pub boundary_sources: Option<Arc<Vec<Vec<acadrust::Handle>>>>,
pub boundary_sources: Option<Arc<Vec<Vec<codec::Handle>>>>,
/// Exact boundary paths retained for persistence and editing.
pub boundary_paths: Option<Arc<Vec<acadrust::entities::BoundaryPath>>>,
pub boundary_paths: Option<Arc<Vec<codec::entities::BoundaryPath>>>,
/// Island handling used by the persisted hatch entity.
pub style: acadrust::entities::HatchStyleType,
pub style: codec::entities::HatchStyleType,
/// Fill pattern.
pub pattern: HatchPattern,
/// Catalog name for this pattern (e.g. "ANSI31", "SOLID", "LINEAR").
@@ -277,14 +277,14 @@ impl HatchModel {
&self,
angle_deg: f32,
shift: f32,
) -> Option<cadkernel::geom2d::GradientFrame> {
) -> Option<kernel::geom2d::GradientFrame> {
let boundary: Vec<[f64; 2]> = self
.boundary
.iter()
.filter(|point| point[0].is_finite() && point[1].is_finite())
.map(|point| [point[0] as f64, point[1] as f64])
.collect();
cadkernel::geom2d::gradient_frame(
kernel::geom2d::gradient_frame(
&boundary,
(angle_deg as f64).to_radians(),
shift as f64,
@@ -309,7 +309,7 @@ impl HatchModel {
rings.push(ring);
}
let (points, triangles) = cadkernel::geom2d::triangulate_rings(&rings);
let (points, triangles) = kernel::geom2d::triangulate_rings(&rings);
let vertices = points
.into_iter()
.map(|[x, y]| [x as f32, y as f32])
+2 -2
View File
@@ -8,8 +8,8 @@ use std::sync::OnceLock;
use crate::io::patterns::PatLineDef;
use crate::scene::model::hatch_model::{HatchPattern, PatFamily};
use acadrust::entities::{HatchPattern as DxfPattern, HatchPatternLine};
use acadrust::types::Vector2;
use codec::entities::{HatchPattern as DxfPattern, HatchPatternLine};
use codec::types::Vector2;
// ── Public types ──────────────────────────────────────────────────────────
+11 -11
View File
@@ -35,8 +35,8 @@ fn quad_verts(corners: &[[f32; 3]; 4], corners_low: &[[f32; 3]; 4]) -> Vec<Image
/// image rectangle when unclipped, else the clip rectangle or the triangulated
/// clip polygon. An inverted (show-outside) boundary isn't a simple filled
/// region, so it falls back to the whole image rather than mis-clip.
fn clip_triangles_px(img: &acadrust::entities::RasterImage) -> Vec<[f64; 2]> {
use acadrust::entities::{ClipMode, ClipType};
fn clip_triangles_px(img: &codec::entities::RasterImage) -> Vec<[f64; 2]> {
use codec::entities::{ClipMode, ClipType};
let w = img.size.x;
let h = img.size.y;
let quad = || {
@@ -115,7 +115,7 @@ impl ImageModel {
/// Build an ImageModel from a DXF RasterImage entity.
/// Returns `None` if the image file cannot be opened or decoded.
pub fn from_raster_image(
img: &acadrust::entities::RasterImage,
img: &codec::entities::RasterImage,
) -> Option<Self> {
let w = img.size.x;
let h = img.size.y;
@@ -196,11 +196,11 @@ impl ImageModel {
/// inverted. `None` when the underlay is off, non-PDF, or the page can't
/// be rendered (caller keeps the outline placeholder).
pub fn from_underlay(
u: &acadrust::entities::Underlay,
def: &acadrust::entities::UnderlayDefinition,
u: &codec::entities::Underlay,
def: &codec::entities::UnderlayDefinition,
background: [f32; 4],
) -> Option<Self> {
use acadrust::entities::{UnderlayDisplayFlags, UnderlayType};
use codec::entities::{UnderlayDisplayFlags, UnderlayType};
use super::pdf_raster::{self, PageAdjust};
if !u.flags.contains(UnderlayDisplayFlags::ON) {
return None;
@@ -290,8 +290,8 @@ impl ImageModel {
/// Visible region of an underlay page as triangles in page UV (0..1, y up):
/// the whole page, the clip polygon, or — for an inverted clip — the page
/// with the polygon cut out.
fn underlay_visible_uv(u: &acadrust::entities::Underlay, page_w: f64, page_h: f64) -> Vec<[f64; 2]> {
use acadrust::entities::UnderlayDisplayFlags;
fn underlay_visible_uv(u: &codec::entities::Underlay, page_w: f64, page_h: f64) -> Vec<[f64; 2]> {
use codec::entities::UnderlayDisplayFlags;
let page = vec![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
let whole = || vec![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
let clip = crate::entities::underlay::clip_polygon_local(u);
@@ -300,9 +300,9 @@ fn underlay_visible_uv(u: &acadrust::entities::Underlay, page_w: f64, page_h: f6
}
let ring: Vec<[f64; 2]> = clip.iter().map(|p| [p[0] / page_w, p[1] / page_h]).collect();
let (points, triangles) = if u.clip_inverted {
cadkernel::geom2d::triangulate(&page, &[ring])
kernel::geom2d::triangulate(&page, &[ring])
} else {
cadkernel::geom2d::triangulate(&ring, &[])
kernel::geom2d::triangulate(&ring, &[])
};
triangles
.into_iter()
@@ -316,7 +316,7 @@ impl ImageModel {
/// metafile picture (rasterized by the `gdi` player); returns `None` when
/// the frame is degenerate or nothing in the blob decodes, so the caller
/// falls back to the frame placeholder.
pub fn from_ole2frame(ole: &acadrust::entities::Ole2Frame) -> Option<Self> {
pub fn from_ole2frame(ole: &codec::entities::Ole2Frame) -> Option<Self> {
let payload = ole.encoded_payload();
let (pixels, width, height) = super::ole_pres::decode(&payload)?;
+8 -8
View File
@@ -1,9 +1,9 @@
//! LOFT command/history integration. Geometry and validation live in the kernel.
use acadrust::entities::{EmbeddedEntity, Point, Surface, SurfaceData, SurfaceKind};
use acadrust::objects::{SolidHistoryLoft, SolidHistoryLoftParameters, SolidHistoryNodeBase};
use acadrust::{EntityType, Handle};
use cadkernel::brep::Body;
use codec::entities::{EmbeddedEntity, Point, Surface, SurfaceData, SurfaceKind};
use codec::objects::{SolidHistoryLoft, SolidHistoryLoftParameters, SolidHistoryNodeBase};
use codec::{EntityType, Handle};
use kernel::brep::Body;
use crate::command::{ExtrudeMode, LoftOptions, LoftSectionSelection};
use super::sweep_model::embedded_path;
@@ -17,11 +17,11 @@ fn embedded_section(entity: &EntityType) -> Option<EmbeddedEntity> {
pub fn is_section(entity: &EntityType) -> bool {
embedded_section(entity).is_some_and(|entity|
cadkernel::acis::loft_section_geometry(&[entity]).is_ok())
kernel::acis::loft_section_geometry(&[entity]).is_ok())
}
pub fn is_guide_or_path(entity: &EntityType) -> bool {
embedded_path(entity).is_some_and(|entity| cadkernel::acis::loft_path_geometry(&entity).is_ok())
embedded_path(entity).is_some_and(|entity| kernel::acis::loft_path_geometry(&entity).is_ok())
}
pub fn record(
@@ -42,7 +42,7 @@ pub fn record(
embedded_section(find(*handle)?).ok_or_else(|| "Unsupported joined loft edge.".to_string())
}).collect::<Result<Vec<_>, _>>()?,
};
if let cadkernel::brep::LoftSection::Profile { closed, .. } = cadkernel::acis::loft_section_geometry(&members)? {
if let kernel::brep::LoftSection::Profile { closed, .. } = kernel::acis::loft_section_geometry(&members)? {
surface |= !closed;
}
section_counts.push(members.len());
@@ -71,7 +71,7 @@ pub fn build_body(
sections: &[LoftSectionSelection], guides: &[Handle], path: Option<Handle>,
available: &[(Handle, EntityType)], mode: ExtrudeMode, options: LoftOptions,
) -> Result<Body, String> {
cadkernel::acis::rebuild_loft_with_options(&record(sections, guides, path, available, mode, options)?)
kernel::acis::rebuild_loft_with_options(&record(sections, guides, path, available, mode, options)?)
}
pub fn surface_entity(record: &SolidHistoryLoft) -> EntityType {
+7 -7
View File
@@ -1,6 +1,6 @@
use acadrust::objects::{Material, MaterialColor, MaterialMap, ObjectType};
use acadrust::xdata::XDataValue;
use acadrust::{CadDocument, EntityType, Handle};
use codec::objects::{Material, MaterialColor, MaterialMap, ObjectType};
use codec::xdata::XDataValue;
use codec::{CadDocument, EntityType, Handle};
use std::path::Path;
use std::sync::Arc;
@@ -581,10 +581,10 @@ fn load_map_image(_map: &MaterialMap, _base_dir: Option<&Path>) -> Option<Arc<Ma
#[cfg(test)]
mod tests {
use super::*;
use acadrust::entities::Line;
use acadrust::objects::MaterialTexture;
use acadrust::types::Vector3;
use acadrust::xdata::{ExtendedDataRecord, XDataValue};
use codec::entities::Line;
use codec::objects::MaterialTexture;
use codec::types::Vector3;
use codec::xdata::{ExtendedDataRecord, XDataValue};
#[test]
fn procedural_checker_is_one_repeatable_two_by_two_tile() {
+13 -13
View File
@@ -21,7 +21,7 @@ pub struct MeshModel {
/// 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>>,
pub triangle_material_handles: Vec<Option<codec::Handle>>,
/// Optional ACIS face colour per triangle, aligned with `indices` triplets.
pub triangle_colors: Vec<Option<[f32; 4]>>,
/// RGBA colour in [0, 1].
@@ -45,7 +45,7 @@ pub struct MeshModel {
/// Kernel-owned source for a view-dependent silhouette.
#[derive(Clone, Debug)]
pub struct CurvedGen {
pub source: cadkernel::brep::mesh::SilhouetteSource,
pub source: kernel::brep::mesh::SilhouetteSource,
}
#[derive(Clone, Copy, Debug, Default)]
@@ -63,7 +63,7 @@ pub struct MeshMetrics {
}
impl MeshMetrics {
fn apply_mass_properties(&mut self, properties: cadkernel::brep::MassProperties) {
fn apply_mass_properties(&mut self, properties: kernel::brep::MassProperties) {
self.volume = properties.volume;
self.centroid = properties.centroid;
self.moment_of_inertia = properties.moment_of_inertia;
@@ -76,7 +76,7 @@ impl MeshMetrics {
pub fn translate(&mut self, delta: [f64; 3]) {
if self.volume > 1e-18 {
self.apply_mass_properties(
cadkernel::brep::MassProperties {
kernel::brep::MassProperties {
volume: self.volume,
centroid: self.centroid,
moment_of_inertia: self.moment_of_inertia,
@@ -106,7 +106,7 @@ pub struct MeshLodSet {
/// `triangle_material_handles`. Only handles actually referenced by the
/// tessellation are retained.
pub face_materials:
rustc_hash::FxHashMap<acadrust::Handle, super::material_model::MeshMaterial>,
rustc_hash::FxHashMap<codec::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>,
@@ -141,9 +141,9 @@ pub struct MeshLodSet {
/// block entity. Top-level meshes leave this empty.
pub instance_source: Option<std::sync::Arc<MeshInstanceSource>>,
/// Accumulated block-local → world transform for this rendered instance.
pub instance_transform: Option<acadrust::types::Transform>,
pub instance_transform: Option<codec::types::Transform>,
/// Parent INSERT selected for this rendered block instance.
pub instance_handle: Option<acadrust::Handle>,
pub instance_handle: Option<codec::Handle>,
/// Effective colour after INSERT inheritance, without copying the mesh.
pub instance_color: Option<[f32; 4]>,
/// Precise world bounds used by the interaction index.
@@ -152,7 +152,7 @@ pub struct MeshLodSet {
#[derive(Clone, Debug)]
pub struct MeshInstanceSource {
pub handle: acadrust::Handle,
pub handle: codec::Handle,
pub lods: Vec<MeshModel>,
pub edge_verts: Vec<[f32; 3]>,
pub edge_verts_low: Vec<[f32; 3]>,
@@ -184,7 +184,7 @@ fn compute_mesh_metrics(lods: &[MeshModel]) -> MeshMetrics {
let Some(mesh) = lods.iter().find(|mesh| !mesh.indices.is_empty()) else {
return MeshMetrics::default();
};
let kernel_mesh = cadkernel::brep::Mesh {
let kernel_mesh = kernel::brep::Mesh {
positions: mesh
.verts
.iter()
@@ -226,7 +226,7 @@ fn compute_mesh_metrics(lods: &[MeshModel]) -> MeshMetrics {
}
impl MeshLodSet {
pub fn apply_mass_properties(&mut self, properties: cadkernel::brep::MassProperties) {
pub fn apply_mass_properties(&mut self, properties: kernel::brep::MassProperties) {
self.metrics.apply_mass_properties(properties);
}
@@ -270,7 +270,7 @@ impl MeshLodSet {
self.z_aabb = z;
}
pub fn prepare_instance_source(&mut self, handle: acadrust::Handle) {
pub fn prepare_instance_source(&mut self, handle: codec::Handle) {
self.instance_source = Some(std::sync::Arc::new(MeshInstanceSource {
handle,
lods: self.lods.clone(),
@@ -300,12 +300,12 @@ impl MeshLodSet {
)
}
pub fn entity_handle(&self) -> Option<acadrust::Handle> {
pub fn entity_handle(&self) -> Option<codec::Handle> {
self.instance_handle.or_else(|| {
self.lods
.first()
.and_then(|mesh| mesh.name.parse::<u64>().ok())
.map(acadrust::Handle::new)
.map(codec::Handle::new)
})
}
+1 -1
View File
@@ -1,6 +1,6 @@
// Shared value types used by the dispatch and grip systems.
use acadrust::types::{Color as AcadColor, Handle, LineWeight};
use codec::types::{Color as AcadColor, Handle, LineWeight};
use glam::DVec3;
/// The kind of value held by a property row.
+2 -2
View File
@@ -1,11 +1,11 @@
// OLE2FRAME binary data → presentation RGBA image.
//
// Extraction (compound-file walk, OlePres header parse, WMFC → EMF
// reassembly) lives in acadrust — `extract_presentation` returns the picture
// reassembly) lives in opencadcodec — `extract_presentation` returns the picture
// bytes tagged by kind. This module only decodes them: rasters through the
// `image` crate, metafiles through the `gdi` player.
use acadrust::entities::{extract_presentation, OlePresentation};
use codec::entities::{extract_presentation, OlePresentation};
use super::gdi;
+3 -3
View File
@@ -231,7 +231,7 @@ fn without_key(dict: &str, key: &str) -> Option<String> {
/// them.
pub const LAYER_OVERRIDE_APP: &str = "AdeskUnderlayLayerOverrideData";
pub fn hidden_layers(u: &acadrust::entities::Underlay) -> Vec<String> {
pub fn hidden_layers(u: &codec::entities::Underlay) -> Vec<String> {
u.common
.extended_data
.records()
@@ -239,14 +239,14 @@ pub fn hidden_layers(u: &acadrust::entities::Underlay) -> Vec<String> {
.filter(|r| r.application_name.eq_ignore_ascii_case(LAYER_OVERRIDE_APP))
.flat_map(|r| r.values.iter())
.filter_map(|v| match v {
acadrust::xdata::XDataValue::String(s) => Some(s.clone()),
codec::xdata::XDataValue::String(s) => Some(s.clone()),
_ => None,
})
.collect()
}
/// The source an underlay's page is read from, with its layer overrides.
pub fn underlay_source(u: &acadrust::entities::Underlay, file_path: &str) -> String {
pub fn underlay_source(u: &codec::entities::Underlay, file_path: &str) -> String {
let hidden = hidden_layers(u);
if hidden.is_empty() {
return file_path.to_string();
+6 -6
View File
@@ -555,11 +555,11 @@ const MAX_SNAP_POINTS: usize = 20_000;
/// Endpoint and midpoint snaps of the underlay's PDF geometry, in world
/// space, when PDFOSNAP is on and the page is shown.
pub fn underlay_snap_points(
u: &acadrust::entities::Underlay,
document: &acadrust::CadDocument,
u: &codec::entities::Underlay,
document: &codec::CadDocument,
) -> Vec<(glam::DVec3, crate::scene::model::wire_model::SnapHint)> {
use crate::scene::model::wire_model::SnapHint;
if !pdf_osnap() || !u.flags.contains(acadrust::entities::UnderlayDisplayFlags::ON) {
if !pdf_osnap() || !u.flags.contains(codec::entities::UnderlayDisplayFlags::ON) {
return Vec::new();
}
let Some(def) = crate::entities::underlay::definition(u, document) else {
@@ -609,10 +609,10 @@ const MAX_GEOMETRY_POINTS: usize = 200_000;
/// flattened) for nearest, intersection and perpendicular snaps. Empty when
/// PDFOSNAP is off or the page is not shown.
pub fn underlay_snap_geometry(
u: &acadrust::entities::Underlay,
document: &acadrust::CadDocument,
u: &codec::entities::Underlay,
document: &codec::CadDocument,
) -> Vec<[f64; 3]> {
if !pdf_osnap() || !u.flags.contains(acadrust::entities::UnderlayDisplayFlags::ON) {
if !pdf_osnap() || !u.flags.contains(codec::entities::UnderlayDisplayFlags::ON) {
return Vec::new();
}
let Some(def) = crate::entities::underlay::definition(u, document) else {
+11 -11
View File
@@ -1,11 +1,11 @@
//! PRESSPULL selection and curve-only previews. Geometry operations stay in the kernel.
use acadrust::entities::{AcisData, EmbeddedEntity, Region, Wire};
use acadrust::types::Vector3;
use acadrust::{EntityType, Handle};
use cadkernel::brep::{self, Body, FaceKey};
use cadkernel::geom2d::{contains, ring_nesting_depths, signed_area, Curve, Line, Tolerance};
use cadkernel::space::Plane;
use codec::entities::{AcisData, EmbeddedEntity, Region, Wire};
use codec::types::Vector3;
use codec::{EntityType, Handle};
use kernel::brep::{self, Body, FaceKey};
use kernel::geom2d::{contains, ring_nesting_depths, signed_area, Curve, Line, Tolerance};
use kernel::space::Plane;
use glam::DVec3;
use rustc_hash::FxHashMap;
@@ -42,7 +42,7 @@ pub fn profile_geometry(entity: &EntityType) -> Option<(Plane, Vec<Vec<Curve>>,
_ => sweep_model::embedded_revolve_profile(entity),
};
if let Some((entity, transform)) = embedded {
if let Ok(geometry) = cadkernel::acis::sweep_profile_geometry(&entity, transform) {
if let Ok(geometry) = kernel::acis::sweep_profile_geometry(&entity, transform) {
return Some(geometry);
}
// Exact modeler data is authoritative, not a hint to replace by chords.
@@ -93,7 +93,7 @@ fn curves_on_plane(source: Plane, curves: &[Curve], plane: WorkingPlane) -> Vec<
let origin = plane.to_local(DVec3::from_array(source.origin));
let x_axis = plane.vector_to_local(DVec3::from_array(source.x_axis));
let y_axis = plane.vector_to_local(DVec3::from_array(source.y_axis));
let transform = cadkernel::geom2d::Transform {
let transform = kernel::geom2d::Transform {
origin: [origin.x, origin.y].into(),
x_axis: [x_axis.x, x_axis.y].into(),
y_axis: [y_axis.x, y_axis.y].into(),
@@ -120,7 +120,7 @@ fn boundary_source(curves: Vec<Curve>) -> Option<BoundarySource> {
length.is_finite() && length > BOUNDARY_TOLERANCE
}).collect::<Vec<_>>();
let segments = curves.iter().flat_map(|curve| {
curve.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
curve.tessellate_angle(kernel::tessellation::DEFAULT_ANGLE)
.windows(2).filter_map(|pair| {
let start = pair[0];
let end = pair[1];
@@ -193,7 +193,7 @@ pub(crate) fn region_from_loops(loops: &[Vec<Curve>], plane: WorkingPlane) -> Op
let mut points = Vec::new();
for curve in ring {
let skip = usize::from(!points.is_empty());
points.extend(curve.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
points.extend(curve.tessellate_angle(kernel::tessellation::DEFAULT_ANGLE)
.into_iter().skip(skip).map(|point| {
let world = kernel_plane.point_at(point);
Vector3::new(world[0], world[1], world[2])
@@ -372,7 +372,7 @@ pub fn preview_wires(target: &PresspullTarget, distance: f64, color: [f32; 4], i
fn preview_body_wires(body: &Body, color: [f32; 4], isolines: usize) -> Vec<WireModel> {
let wireframe = brep::mesh::tessellate_wireframe(body,
brep::mesh::TessellationTolerance::new(cadkernel::tessellation::DEFAULT_ANGLE, 1e-9)
brep::mesh::TessellationTolerance::new(kernel::tessellation::DEFAULT_ANGLE, 1e-9)
.with_isolines(isolines));
wireframe.edges.into_iter().map(|edge| edge.positions)
.chain(wireframe.isolines.into_iter().map(|line| line.positions))
+67 -67
View File
@@ -1,13 +1,13 @@
use acadrust::entities::{EmbeddedEntity, Solid3D};
use acadrust::objects::{
use codec::entities::{EmbeddedEntity, Solid3D};
use codec::objects::{
DynamicBlockData, ObjectType, SolidHistoryBox, SolidHistoryBrep, SolidHistoryChamfer,
SolidHistoryCone, SolidHistoryCylinder, SolidHistoryFillet, SolidHistoryLoft,
SolidHistoryLoftParameters, SolidHistoryNodeBase, SolidHistoryOperation,
SolidHistoryPyramid, SolidHistoryRevolve, SolidHistorySphere, SolidHistorySweep,
SolidHistoryTorus,
};
use acadrust::EntityType;
use cadkernel::brep::{Body, Surface};
use codec::EntityType;
use kernel::brep::{Body, Surface};
use crate::command::EntityTransform;
use crate::entities::traits::EntityTypeOps;
@@ -129,8 +129,8 @@ fn compact_surface_number(mut value: String) -> String {
}
fn history_flags(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Option<(bool, bool, i16)> {
let graph = document.solid_history_graph(handle)?;
let ObjectType::DynamicBlock(object) = document.objects.get(&graph.root)? else {
@@ -222,8 +222,8 @@ fn revolve_direction_property(
}
pub fn has_specialized_primitive_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> bool {
matches!(
primitive_property_operation(document, handle).as_ref(),
@@ -247,8 +247,8 @@ pub fn has_specialized_primitive_properties(
/// operations refine that primitive without replacing its editable type,
/// position, or dimensions.
pub fn primitive_property_operation(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Option<SolidHistoryOperation> {
document
.solid_history_operations(handle)
@@ -261,12 +261,12 @@ pub fn primitive_property_operation(
/// no stable primitive dimensions to expose, but it still uses the compact
/// Solid History palette rather than the internal ACIS/cache diagnostics.
pub fn has_compact_solid_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> bool {
match document.get_entity(handle) {
Some(acadrust::EntityType::Solid3D(_)) => true,
Some(acadrust::EntityType::Surface(_)) => matches!(
Some(codec::EntityType::Solid3D(_)) => true,
Some(codec::EntityType::Surface(_)) => matches!(
primitive_property_operation(document, handle),
Some(SolidHistoryOperation::Extrusion(_))
),
@@ -285,7 +285,7 @@ pub fn reference_point(operation: &SolidHistoryOperation) -> Option<glam::DVec3>
}
SolidHistoryOperation::Cone(value) => world_point(value.base.transform, [0.0; 3]),
SolidHistoryOperation::Cylinder(value) => world_point(value.base.transform, [0.0; 3]),
SolidHistoryOperation::Sweep(value) => cadkernel::acis::sweep_history_reference_point(value)
SolidHistoryOperation::Sweep(value) => kernel::acis::sweep_history_reference_point(value)
.ok().map(glam::DVec3::from_array),
SolidHistoryOperation::Extrusion(value) => world_point(
value.base.transform,
@@ -306,8 +306,8 @@ pub fn reference_point(operation: &SolidHistoryOperation) -> Option<glam::DVec3>
}
fn revolve_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryRevolve,
) -> Vec<PropSection> {
let Some(axis_position) = world_point(
@@ -416,8 +416,8 @@ fn revolve_properties(
}
fn extrusion_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistorySweep,
) -> Vec<PropSection> {
let direction = matrix(value.base.transform).map(|transform| {
@@ -629,8 +629,8 @@ fn extrusion_properties(
/// direction and taper used by the extrusion history rebuild.
pub fn extrusion_surface_data(
value: &SolidHistorySweep,
) -> Option<acadrust::entities::SurfaceData> {
use acadrust::entities::{SurfaceData, SurfaceSweepOptions};
) -> Option<codec::entities::SurfaceData> {
use codec::entities::{SurfaceData, SurfaceSweepOptions};
if value.path_entity.is_some() {
return None;
@@ -663,8 +663,8 @@ pub fn extrusion_surface_data(
}
fn sweep_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistorySweep,
) -> Vec<PropSection> {
let (record_history, object_show_history, show_history_mode) =
@@ -672,7 +672,7 @@ fn sweep_properties(
let (show_history, show_history_editable) =
displayed_history_state(object_show_history, show_history_mode);
let show_value = if show_history { "Yes" } else { "No" };
let length = cadkernel::acis::sweep_history_path_length(value).ok()
let length = kernel::acis::sweep_history_path_length(value).ok()
.map(crate::entities::common::format_length)
.unwrap_or_default();
vec![
@@ -776,8 +776,8 @@ pub fn loft_closed_editable(value: &SolidHistoryLoft) -> bool {
}
fn loft_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryLoft,
) -> Vec<PropSection> {
let parameters = loft_parameters(value);
@@ -901,8 +901,8 @@ fn loft_properties(
}
fn sweep_path_length(value: &SolidHistorySweep) -> Option<f64> {
use acadrust::entities::EmbeddedEntity;
use acadrust::EntityType;
use codec::entities::EmbeddedEntity;
use codec::EntityType;
let path_entity = value.path_entity.as_ref()?;
if let EmbeddedEntity::Spline(path) = path_entity {
@@ -946,7 +946,7 @@ fn sweep_path_length(value: &SolidHistorySweep) -> Option<f64> {
{
return None;
}
let placement = cadkernel::brep::Placement {
let placement = kernel::brep::Placement {
x_axis: [transform[0], transform[1], transform[2]],
y_axis: [transform[4], transform[5], transform[6]],
z_axis: [transform[8], transform[9], transform[10]],
@@ -957,8 +957,8 @@ fn sweep_path_length(value: &SolidHistorySweep) -> Option<f64> {
}
fn torus_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryTorus,
) -> Vec<PropSection> {
let Some(position) = world_point(value.base.transform, [0.0; 3]) else {
@@ -1026,8 +1026,8 @@ fn torus_properties(
}
fn cone_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryCone,
) -> Vec<PropSection> {
let Some(position) = world_point(value.base.transform, [0.0; 3]) else {
@@ -1160,8 +1160,8 @@ fn cone_properties(
}
fn brep_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Vec<PropSection> {
let (record_history, object_show_history, show_history_mode) =
history_flags(document, handle).unwrap_or((false, false, 1));
@@ -1195,8 +1195,8 @@ fn brep_properties(
}
fn cylinder_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryCylinder,
) -> Vec<PropSection> {
let Some(position) = world_point(value.base.transform, [0.0; 3]) else {
@@ -1333,8 +1333,8 @@ fn pyramid_display_rotation(value: &SolidHistoryPyramid) -> Option<f64> {
}
fn pyramid_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryPyramid,
) -> Vec<PropSection> {
let Some(position) = world_point(value.base.transform, [0.0; 3]) else {
@@ -1433,8 +1433,8 @@ fn pyramid_properties(
}
fn sphere_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistorySphere,
) -> Vec<PropSection> {
let Some(position) = world_point(value.base.transform, [0.0; 3]) else {
@@ -1510,8 +1510,8 @@ fn sphere_properties(
}
fn rectangular_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryBox,
solid_type: &str,
) -> Vec<PropSection> {
@@ -1606,12 +1606,12 @@ fn rectangular_properties(
}
pub fn primitive_properties(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Vec<PropSection> {
if !matches!(
document.get_entity(handle),
Some(acadrust::EntityType::Solid3D(_) | acadrust::EntityType::Surface(_))
Some(codec::EntityType::Solid3D(_) | codec::EntityType::Surface(_))
) {
return Vec::new();
}
@@ -1772,7 +1772,7 @@ fn apply_extrusion_geometry_property(
if (updated - direction).length_squared() <= 1e-24 {
return Some(false);
}
value.direction = acadrust::types::Vector3::new(updated.x, updated.y, updated.z);
value.direction = codec::types::Vector3::new(updated.x, updated.y, updated.z);
value.end_draft_distance = height;
Some(true)
}
@@ -1837,7 +1837,7 @@ fn apply_revolve_geometry_property(
if !local.is_finite() {
return Some(false);
}
value.axis_point = acadrust::types::Vector3::new(local.x, local.y, local.z);
value.axis_point = codec::types::Vector3::new(local.x, local.y, local.z);
return Some(true);
}
@@ -1895,7 +1895,7 @@ fn apply_revolve_geometry_property(
if (local - current).length_squared() <= 1e-24 {
return Some(false);
}
value.direction = acadrust::types::Vector3::new(local.x, local.y, local.z);
value.direction = codec::types::Vector3::new(local.x, local.y, local.z);
return Some(true);
}
@@ -1903,8 +1903,8 @@ fn apply_revolve_geometry_property(
}
pub fn apply_history_choice(
document: &mut acadrust::CadDocument,
handle: acadrust::Handle,
document: &mut codec::CadDocument,
handle: codec::Handle,
field: &str,
value: &str,
) -> bool {
@@ -2667,7 +2667,7 @@ fn matrix(transform: [f64; 16]) -> Option<glam::DMat4> {
(matrix.is_finite() && matrix.determinant().abs() > 1e-12).then_some(matrix)
}
fn codec_matrix(transform: &acadrust::types::Transform) -> glam::DMat4 {
fn codec_matrix(transform: &codec::types::Transform) -> glam::DMat4 {
let matrix = transform.matrix.m;
glam::DMat4::from_cols_array(&[
matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
@@ -2764,8 +2764,8 @@ fn embedded_entity(value: &EmbeddedEntity) -> Option<EntityType> {
/// Visible LOFT construction curves, owned by the parent display entity.
/// Copies are transformed to WCS and never inserted into the document.
pub fn loft_visible_history_entities(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Vec<EntityType> {
let Some((_, object_show_history, show_history_mode)) = history_flags(document, handle) else {
return Vec::new();
@@ -2783,8 +2783,8 @@ pub fn loft_visible_history_entities(
return Vec::new();
};
let columns = transform.to_cols_array_2d();
let affine = acadrust::types::Transform::from_matrix(
acadrust::types::Matrix4 {
let affine = codec::types::Transform::from_matrix(
codec::types::Matrix4 {
m: std::array::from_fn(|row| std::array::from_fn(|column| columns[column][row])),
},
);
@@ -2911,8 +2911,8 @@ fn apply_extrusion_profile_grip(
}
fn sweep_placement_matrices(value: &SolidHistorySweep) -> Option<(glam::DMat4, glam::DMat4)> {
let (profile, path) = cadkernel::acis::sweep_history_placements(value).ok()?;
let matrix = |place: cadkernel::brep::Placement| {
let (profile, path) = kernel::acis::sweep_history_placements(value).ok()?;
let matrix = |place: kernel::brep::Placement| {
glam::DMat4::from_cols(
glam::DVec3::from_array(place.x_axis).extend(0.0),
glam::DVec3::from_array(place.y_axis).extend(0.0),
@@ -3286,12 +3286,12 @@ fn extrusion_draft_rebuilds(value: &SolidHistorySweep, angle: f64) -> bool {
let Some(profile) = candidate.sweep_entity.as_ref() else {
return false;
};
let Ok((_, _, closed)) = cadkernel::acis::sweep_profile_geometry(
let Ok((_, _, closed)) = kernel::acis::sweep_profile_geometry(
profile, candidate.sweep_entity_transform,
) else {
return false;
};
cadkernel::acis::rebuild_extrusion_with_mode(&candidate, !closed).is_ok()
kernel::acis::rebuild_extrusion_with_mode(&candidate, !closed).is_ok()
}
fn grip(
@@ -3356,8 +3356,8 @@ pub fn fillet_radius_grip(body: &Body, radius: f64) -> Option<GripDef> {
}
pub fn chamfer_distance_grips(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
value: &SolidHistoryChamfer,
) -> Vec<GripDef> {
let Some(operations) = document.solid_history_operations(handle) else {
@@ -3369,7 +3369,7 @@ pub fn chamfer_distance_grips(
else {
return Vec::new();
};
let Ok(source) = cadkernel::acis::rebuild_history(&operations[..chamfer_index]) else {
let Ok(source) = kernel::acis::rebuild_history(&operations[..chamfer_index]) else {
return Vec::new();
};
let edges = source.edge_keys().collect::<Vec<_>>();
@@ -3454,8 +3454,8 @@ pub fn chamfer_distance_grips(
}
pub fn primitive_grips(
document: &acadrust::CadDocument,
handle: acadrust::Handle,
document: &codec::CadDocument,
handle: codec::Handle,
) -> Vec<GripDef> {
let Some(operation) = document.solid_history_operation(handle) else {
return Vec::new();
@@ -3920,7 +3920,7 @@ pub fn apply_primitive_grip(
_ => return false,
},
SolidHistoryOperation::Revolve(value) if grip_id == GRIP_REVOLVE_AXIS => {
value.axis_point = acadrust::types::Vector3::new(local.x, local.y, local.z);
value.axis_point = codec::types::Vector3::new(local.x, local.y, local.z);
}
SolidHistoryOperation::Extrusion(value) => match grip_id {
GRIP_HEIGHT => {
@@ -3948,7 +3948,7 @@ pub fn apply_primitive_grip(
if (direction - current).length_squared() <= 1e-24 {
return false;
}
value.direction = acadrust::types::Vector3::new(
value.direction = codec::types::Vector3::new(
direction.x,
direction.y,
direction.z,
+20 -20
View File
@@ -1,6 +1,6 @@
// Kernel B-rep construction and display tessellation.
use cadkernel::brep::{self, Body, Curve3, EdgeKey, FaceKey, Surface};
use kernel::brep::{self, Body, Curve3, EdgeKey, FaceKey, Surface};
use crate::scene::model::mesh_model::{MeshLodSet, MeshModel};
use crate::scene::model::wire_model::WireModel;
@@ -12,7 +12,7 @@ fn tessellation(body: &Body) -> brep::mesh::BodyMesh {
brep::mesh::tessellate(
body,
brep::mesh::TessellationTolerance::new(
cadkernel::tessellation::DEFAULT_ANGLE,
kernel::tessellation::DEFAULT_ANGLE,
TOL,
),
)
@@ -31,8 +31,8 @@ fn display_tessellation(
1.0
};
let max_angle = chordal_deflection.map_or_else(
|| cadkernel::tessellation::angle_for_resolution(resolution),
|_| cadkernel::tessellation::display_angle_for_resolution(resolution),
|| kernel::tessellation::angle_for_resolution(resolution),
|_| kernel::tessellation::display_angle_for_resolution(resolution),
);
let mut tolerance = brep::mesh::TessellationTolerance::new(max_angle, TOL)
.with_uv_isolines(isolines[0], isolines[1])
@@ -251,15 +251,15 @@ pub fn section(body: &Body, axis: usize, value: f64) -> Vec<([f64; 3], [f64; 3])
// ── Edge extraction (pick geometry + wireframe overlay) ─────────────────────
/// Tessellate the solid's B-rep edges into acadrust `Wire`s. Stored on the
/// Tessellate the solid's B-rep edges into opencadcodec `Wire`s. Stored on the
/// `Solid3D`/result entity for picking.
pub fn edge_wires(body: &Body) -> Vec<acadrust::entities::Wire> {
use acadrust::types::Vector3;
pub fn edge_wires(body: &Body) -> Vec<codec::entities::Wire> {
use codec::types::Vector3;
tessellation(body)
.edges
.iter()
.map(|edge| {
acadrust::entities::Wire::from_points(
codec::entities::Wire::from_points(
edge.positions
.iter()
.map(|p| Vector3::new(p[0], p[1], p[2]))
@@ -277,14 +277,14 @@ pub fn edge_wires(body: &Body) -> Vec<acadrust::entities::Wire> {
/// is presented as a separate, non-pickable outline until placement.
pub fn grip_preview_wires(
body: &Body,
handle: acadrust::Handle,
handle: codec::Handle,
isolines: [usize; 2],
planar_isolines: bool,
) -> Vec<WireModel> {
let tessellation = brep::mesh::tessellate(
body,
brep::mesh::TessellationTolerance::new(
cadkernel::tessellation::DEFAULT_ANGLE,
kernel::tessellation::DEFAULT_ANGLE,
TOL,
)
.with_uv_isolines(isolines[0], isolines[1])
@@ -314,14 +314,14 @@ pub fn grip_preview_wires(
/// B-rep edge nearest a world-space surface pick.
pub fn nearest_edge(body: &Body, pick: [f64; 3]) -> Option<EdgeKey> {
let pick = cadkernel::space::Vec3::from(pick);
let pick = kernel::space::Vec3::from(pick);
body.edge_keys()
.filter_map(|key| {
let edge = body.edges.get(key)?;
let curve = body.curves.get(edge.curve)?;
let nearest = if matches!(curve, Curve3::Line(_)) {
let start = cadkernel::space::Vec3::from(curve.point_at(edge.start_parameter));
let end = cadkernel::space::Vec3::from(curve.point_at(edge.end_parameter));
let start = kernel::space::Vec3::from(curve.point_at(edge.start_parameter));
let end = kernel::space::Vec3::from(curve.point_at(edge.end_parameter));
let span = end - start;
let length2 = span.dot(span);
let along = if length2 > 0.0 {
@@ -336,7 +336,7 @@ pub fn nearest_edge(body: &Body, pick: [f64; 3]) -> Option<EdgeKey> {
.map(|step| {
let t = edge.start_parameter
+ (edge.end_parameter - edge.start_parameter) * step as f64 / 64.0;
pick.distance(cadkernel::space::Vec3::from(curve.point_at(t)))
pick.distance(kernel::space::Vec3::from(curve.point_at(t)))
})
.fold(f64::INFINITY, f64::min)
};
@@ -367,7 +367,7 @@ pub fn planar_face_normal(body: &Body, face: FaceKey) -> Option<[f64; 3]> {
let Surface::Plane(plane) = body.surfaces.get(face.surface)? else {
return None;
};
let normal = cadkernel::space::Vec3::from(plane.normal()?);
let normal = kernel::space::Vec3::from(plane.normal()?);
Some(if face.forward { normal } else { -normal }.to_array())
}
@@ -518,8 +518,8 @@ pub fn display_from_solid(
chordal_deflection: Option<f64>,
isolines: [usize; 2],
planar_isolines: bool,
) -> Option<(MeshLodSet, Vec<acadrust::entities::Wire>, [f64; 3])> {
use acadrust::types::Vector3;
) -> Option<(MeshLodSet, Vec<codec::entities::Wire>, [f64; 3])> {
use codec::types::Vector3;
let tessellation = display_tessellation(
body,
facet_resolution,
@@ -532,7 +532,7 @@ pub fn display_from_solid(
.edges
.iter()
.map(|edge| {
acadrust::entities::Wire::from_points(
codec::entities::Wire::from_points(
edge.positions
.iter()
.map(|point| Vector3::new(point[0], point[1], point[2]))
@@ -541,7 +541,7 @@ pub fn display_from_solid(
})
.collect();
let mut mesh = mesh_from_tessellation(tessellation, color)?;
if let Some(properties) = cadkernel::brep::analytic_mass_properties(body) {
if let Some(properties) = kernel::brep::analytic_mass_properties(body) {
mesh.apply_mass_properties(properties);
}
Some((mesh, wires, center))
@@ -583,7 +583,7 @@ fn mesh_center(mesh: &brep::mesh::Mesh) -> Option<[f64; 3]> {
/// exists to test with.
#[cfg(test)]
pub fn volume(body: &Body) -> f64 {
use cadkernel::space::Vec3;
use kernel::space::Vec3;
let mesh = tessellation(body).mesh;
let Some(middle) = centre(body) else {
return 0.0;
+15 -15
View File
@@ -1,17 +1,17 @@
//! SWEEP command data mapped to the shared kernel history reconstruction.
use acadrust::entities::{Surface, SurfaceData, SurfaceKind, SurfaceSweepOptions};
use acadrust::objects::{SolidHistoryNodeBase, SolidHistorySweep};
use acadrust::types::Vector3;
use acadrust::EntityType;
use cadkernel::brep::Body;
use codec::entities::{Surface, SurfaceData, SurfaceKind, SurfaceSweepOptions};
use codec::objects::{SolidHistoryNodeBase, SolidHistorySweep};
use codec::types::Vector3;
use codec::EntityType;
use kernel::brep::Body;
use crate::command::{ExtrudeMode, SweepOptions};
use super::sweep_model::{embedded_path, embedded_revolve_profile};
fn embedded_sweep_profile(entity: &EntityType) -> Option<(acadrust::entities::EmbeddedEntity, [f64; 16])> {
fn embedded_sweep_profile(entity: &EntityType) -> Option<(codec::entities::EmbeddedEntity, [f64; 16])> {
if let EntityType::Region(region) = entity {
Some((acadrust::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array()))
Some((codec::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array()))
} else {
embedded_revolve_profile(entity)
}
@@ -19,13 +19,13 @@ fn embedded_sweep_profile(entity: &EntityType) -> Option<(acadrust::entities::Em
pub fn is_sweep_profile(entity: &EntityType) -> bool {
embedded_sweep_profile(entity).is_some_and(|(profile, transform)| {
cadkernel::acis::sweep_profile_geometry(&profile, transform).is_ok()
kernel::acis::sweep_profile_geometry(&profile, transform).is_ok()
})
}
pub fn is_sweep_path(entity: &EntityType) -> bool {
match embedded_path(entity) {
Some(acadrust::entities::EmbeddedEntity::Spline(value)) => {
Some(codec::entities::EmbeddedEntity::Spline(value)) => {
value.degree > 0 && (value.control_points.len() > value.degree as usize
|| value.fit_points.len() >= 2)
}
@@ -42,21 +42,21 @@ pub fn sweep_selection_options(profiles: &[EntityType], mut options: SweepOption
}
let geometry = profiles.iter().map(|profile| {
let (entity, transform) = embedded_sweep_profile(profile)?;
let (plane, wires, _) = cadkernel::acis::sweep_profile_geometry(&entity, transform).ok()?;
let (plane, wires, _) = kernel::acis::sweep_profile_geometry(&entity, transform).ok()?;
Some((plane, wires))
}).collect::<Option<Vec<_>>>()?;
options.base_point = Some(glam::DVec3::from_array(
cadkernel::brep::sweep_profile_group_base(&geometry)?,
kernel::brep::sweep_profile_group_base(&geometry)?,
));
Some(options)
}
pub fn sweep_record(profile: &EntityType, path: &EntityType, options: SweepOptions) -> Option<SolidHistorySweep> {
let (sweep_entity, sweep_entity_transform) = embedded_sweep_profile(profile)?;
let (plane, wires, _) = cadkernel::acis::sweep_profile_geometry(&sweep_entity, sweep_entity_transform).ok()?;
let (plane, wires, _) = kernel::acis::sweep_profile_geometry(&sweep_entity, sweep_entity_transform).ok()?;
let base_point = match options.base_point {
Some(point) => point.to_array(),
None => cadkernel::brep::sweep_profile_base(plane, &wires)?,
None => kernel::brep::sweep_profile_base(plane, &wires)?,
};
let mut base = SolidHistoryNodeBase::new(1);
base.transform = glam::DMat4::IDENTITY.to_cols_array();
@@ -79,13 +79,13 @@ pub fn sweep_record(profile: &EntityType, path: &EntityType, options: SweepOptio
pub fn swept_with_options(profile: &EntityType, path: &EntityType, mode: ExtrudeMode, options: SweepOptions) -> Option<Body> {
let record = sweep_record(profile, path, options)?;
cadkernel::acis::rebuild_sweep_with_mode(&record, mode == ExtrudeMode::Surface).ok()
kernel::acis::rebuild_sweep_with_mode(&record, mode == ExtrudeMode::Surface).ok()
}
/// Preserve native construction parameters alongside the sheet's saved B-rep.
pub fn swept_surface_entity(record: &SolidHistorySweep) -> EntityType {
let mut surface = Surface::new(SurfaceKind::Swept);
if let Ok(point) = cadkernel::acis::sweep_history_reference_point(record) {
if let Ok(point) = kernel::acis::sweep_history_reference_point(record) {
surface.point_of_reference = Vector3::new(point[0], point[1], point[2]);
}
surface.surface_data = SurfaceData::Swept {
+14 -14
View File
@@ -1,15 +1,15 @@
// Exact profile sweeps stored as kernel B-reps and ACIS.
use cadkernel::brep::{self, Body};
use cadkernel::geom2d::{Arc, Curve, EllipseArc, Line};
use cadkernel::space::{PlanarCurve, Plane, Vec3};
use acadrust::entities::{EmbeddedEntity, LwPolyline, LwVertex, Spline};
use acadrust::objects::{
use kernel::brep::{self, Body};
use kernel::geom2d::{Arc, Curve, EllipseArc, Line};
use kernel::space::{PlanarCurve, Plane, Vec3};
use codec::entities::{EmbeddedEntity, LwPolyline, LwVertex, Spline};
use codec::objects::{
SolidHistoryLoft, SolidHistoryNodeBase, SolidHistoryOperation, SolidHistoryRevolve,
SolidHistorySweep,
};
use acadrust::types::{Vector2, Vector3};
use acadrust::EntityType;
use codec::types::{Vector2, Vector3};
use codec::EntityType;
use crate::entities::curve::entity_curve;
pub use super::sweep_command_model::{
@@ -148,7 +148,7 @@ fn planar_polygon_entity(entity: &EntityType) -> Option<PlanarCurve> {
let vertices = points
.iter()
.map(|point| {
plane.project(*point).map(|position| cadkernel::geom2d::PolylineVertex {
plane.project(*point).map(|position| kernel::geom2d::PolylineVertex {
position,
bulge: 0.0,
})
@@ -156,7 +156,7 @@ fn planar_polygon_entity(entity: &EntityType) -> Option<PlanarCurve> {
.collect::<Option<Vec<_>>>()?;
Some(PlanarCurve::new(
plane,
Curve::Polyline(cadkernel::geom2d::Polyline { vertices, closed }),
Curve::Polyline(kernel::geom2d::Polyline { vertices, closed }),
))
}
@@ -194,14 +194,14 @@ fn region_profiles(entity: &EntityType) -> Option<(Plane, Vec<Vec<Curve>>)> {
.map(|point| {
plane
.project(*point)
.map(|position| cadkernel::geom2d::PolylineVertex {
.map(|position| kernel::geom2d::PolylineVertex {
position,
bulge: 0.0,
})
})
.collect::<Option<Vec<_>>>()?;
profiles.push(
Curve::Polyline(cadkernel::geom2d::Polyline {
Curve::Polyline(kernel::geom2d::Polyline {
vertices,
closed: true,
})
@@ -810,7 +810,7 @@ pub fn polysolid(
reference_point: Vector3::new(start.x, start.y, start.z),
..SolidHistorySweep::default()
});
let body = cadkernel::acis::rebuild_body(&operation).ok()?;
let body = kernel::acis::rebuild_body(&operation).ok()?;
Some((body, operation))
}
@@ -892,8 +892,8 @@ fn circular_loft(profiles: &[EntityType]) -> Option<Body> {
#[cfg(test)]
mod tests {
use super::*;
use acadrust::entities::{Circle, LwPolyline, LwVertex};
use acadrust::types::{Vector2, Vector3};
use codec::entities::{Circle, LwPolyline, LwVertex};
use codec::types::{Vector2, Vector3};
fn square(size: f64) -> EntityType {
let mut polyline = LwPolyline::new();
+3 -3
View File
@@ -1,7 +1,7 @@
use acadrust::objects::{
use codec::objects::{
ObjectType, VisualStyle, VisualStyleProperty, VisualStylePropertyValue,
};
use acadrust::{CadDocument, EntityType, Handle};
use codec::{CadDocument, EntityType, Handle};
#[derive(Clone, Debug)]
pub struct MeshVisualStyle {
@@ -102,7 +102,7 @@ fn property_color(style: &VisualStyle, index: usize) -> Option<[f32; 4]> {
};
if matches!(
color,
acadrust::types::Color::ByLayer | acadrust::types::Color::ByBlock
codec::types::Color::ByLayer | codec::types::Color::ByBlock
) {
return None;
}
+1 -1
View File
@@ -443,7 +443,7 @@ pub struct WireModel {
/// Empty for tessellated curves (Circle, Arc, Ellipse) which use snap_pts instead.
pub key_vertices: Vec<[f64; 3]>,
/// World-space 2-D bounding box [min_x, min_y, max_x, max_y].
/// Set from acadrust `bounding_box()` in `tessellate_entity()`.
/// Set from opencadcodec `bounding_box()` in `tessellate_entity()`.
/// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected
/// by the snap world-space filter.
pub aabb: [f32; 4],