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

+2 -2
View File
@@ -1,4 +1,4 @@
// acadrust entity -> what the renderer draws.
// opencadcodec entity -> what the renderer draws.
//
// Every entity becomes one of a handful of shapes: a run of points, a run of
// text strokes, a band of varying width, or a single dot. Curved entities are
@@ -6,7 +6,7 @@
// defined once — so a circle drawn here and a circle extruded by the Model
// tab come from the same definition and cannot disagree.
use acadrust::{CadDocument, EntityType};
use codec::{CadDocument, EntityType};
use crate::entities::traits::EntityTypeOps;
use crate::scene::model::wire_model::{SnapHint, TangentGeom};
+10 -10
View File
@@ -2,9 +2,9 @@
//!
//! Analytic surfaces remain analytic instead of becoming facets.
use cadkernel::acis::append;
use acadrust::entities::acis::{SabReader, SabWriter, SatDocument};
use cadkernel::brep::Body;
use kernel::acis::append;
use codec::entities::acis::{SabReader, SabWriter, SatDocument};
use kernel::brep::Body;
/// Returns `None` when the body contains an unsupported record form.
pub fn solid_to_sat(body: &Body) -> Option<SatDocument> {
@@ -12,7 +12,7 @@ pub fn solid_to_sat(body: &Body) -> Option<SatDocument> {
append(body, &mut document).ok()?;
let document = SatDocument::parse(&document.to_sat_string()).ok()?;
let valid = |candidate: &SatDocument| {
let (restored, loss) = cadkernel::acis::lift(candidate);
let (restored, loss) = kernel::acis::lift(candidate);
loss.is_empty() && restored.len() == 1 && restored[0].validate().is_empty()
};
if !valid(&document) {
@@ -25,8 +25,8 @@ pub fn solid_to_sat(body: &Body) -> Option<SatDocument> {
#[cfg(test)]
mod tests {
use super::*;
use cadkernel::geom2d::{Arc, Curve};
use cadkernel::space::Plane;
use kernel::geom2d::{Arc, Curve};
use kernel::space::Plane;
fn circle_section(z: f64, radius: f64) -> (Plane, Vec<Curve>) {
let curves = (0..4)
@@ -48,7 +48,7 @@ mod tests {
#[test]
fn a_curved_loft_round_trips_through_text_and_binary_acis() {
let body = cadkernel::brep::loft(&[
let body = kernel::brep::loft(&[
circle_section(0.0, 5.0),
circle_section(10.0, 2.0),
])
@@ -56,17 +56,17 @@ mod tests {
assert!(body.validate().is_empty());
let mut document = SatDocument::new();
cadkernel::acis::append(&body, &mut document).unwrap();
kernel::acis::append(&body, &mut document).unwrap();
let text = document.to_sat_string();
let parsed = SatDocument::parse(&text).unwrap();
let (restored, text_loss) = cadkernel::acis::lift(&parsed);
let (restored, text_loss) = kernel::acis::lift(&parsed);
assert!(text_loss.is_empty(), "{text_loss:?}");
assert_eq!(restored.len(), 1);
assert!(restored[0].validate().is_empty());
let binary = SabWriter::write(&parsed);
let parsed_binary = SabReader::read(&binary).unwrap();
let (restored, binary_loss) = cadkernel::acis::lift(&parsed_binary);
let (restored, binary_loss) = kernel::acis::lift(&parsed_binary);
assert!(binary_loss.is_empty(), "{binary_loss:?}");
assert_eq!(restored.len(), 1);
assert!(restored[0].validate().is_empty());
+9 -9
View File
@@ -8,9 +8,9 @@
//!
//! Lift and tessellation failures are reported as an incomplete result.
use cadkernel::acis::lift;
use acadrust::entities::acis::SatDocument;
use cadkernel::brep;
use kernel::acis::lift;
use codec::entities::acis::SatDocument;
use kernel::brep;
use crate::scene::convert::solid3d_tess::{body_transform, finalize_mesh};
use crate::scene::model::mesh_model::{CurvedGen, MeshLodSet};
@@ -56,8 +56,8 @@ pub fn tessellate_sat(
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),
);
// Positions stay f64 until `finalize_mesh` splits them into the coarse
@@ -69,7 +69,7 @@ pub fn tessellate_sat(
let mut triangle_materials = Vec::new();
let mut triangle_colors = Vec::new();
let mut curved_gens = Vec::new();
let face_materials: std::collections::HashMap<i32, acadrust::Handle> = document
let face_materials: std::collections::HashMap<i32, codec::Handle> = document
.records
.iter()
.filter(|record| record.entity_type == "material-adesk-attrib")
@@ -77,7 +77,7 @@ pub fn tessellate_sat(
let owner = record.token_pointer(2)?.0;
let handle = record.token(3)?.as_integer()?;
(owner >= 0 && handle > 0)
.then(|| (owner, acadrust::Handle::new(handle as u64)))
.then(|| (owner, codec::Handle::new(handle as u64)))
})
.collect();
let face_colors: std::collections::HashMap<i32, [f32; 4]> = document
@@ -88,9 +88,9 @@ pub fn tessellate_sat(
let owner = record.token_pointer(2)?.0;
let value = record.token(3)?.as_integer()?;
let source = if (1..=255).contains(&value) {
acadrust::Color::from_index(value as i16)
codec::Color::from_index(value as i16)
} else if value > 257 {
acadrust::Color::from_true_color_value(value as i32)
codec::Color::from_true_color_value(value as i32)
} else {
return None;
};
+6 -6
View File
@@ -2,18 +2,18 @@
//!
//! Imported DGN linetypes store their real pattern as DGN
//! line-style objects (`AcDbLS*`), not standard `LTYPE` dashes — the standard
//! table entry is empty, so acadrust exposes the structure in
//! table entry is empty, so opencadcodec exposes the structure in
//! [`CadDocument::dgn_ls_definitions`] / `dgn_ls_components` instead. See
//! `objects/dgn_linestyle.rs` in acadrust and `~/Documents/OCS/DGN_LINESTYLE_PLAN.md`.
//! `objects/dgn_linestyle.rs` in opencadcodec and `~/Documents/OCS/DGN_LINESTYLE_PLAN.md`.
//!
//! The visible content combines **symbol components**, each of which references
//! an anonymous block (e.g. a pipe's end circle), with typed stroke patterns.
//! Symbols are rendered at the host polyline's endpoints and stroke dash/gap
//! lengths are carried through to the pipe walls.
use acadrust::objects::DgnLsComponentType;
use acadrust::types::{Handle, Vector3};
use acadrust::{CadDocument, EntityType};
use codec::objects::DgnLsComponentType;
use codec::types::{Handle, Vector3};
use codec::{CadDocument, EntityType};
use std::collections::HashSet;
use crate::scene::model::wire_model::WireModel;
@@ -75,7 +75,7 @@ fn walk(doc: &CadDocument, h: Handle, out: &mut Vec<DgnSymbol>, seen: &mut HashS
/// Signed native dash lengths in a typed stroke component: dashes are positive
/// and gaps negative. Empty when the component has no usable stroke lengths.
fn stroke_dashes(doc: &CadDocument, h: Handle) -> Vec<f64> {
use acadrust::objects::{DgnLineStyleData, DgnLsComponentData, ObjectType};
use codec::objects::{DgnLineStyleData, DgnLsComponentData, ObjectType};
let Some(ObjectType::DgnLineStyle(style)) = doc.objects.get(&h)
else {
return Vec::new();
+9 -9
View File
@@ -1,6 +1,6 @@
use acadrust::entities::acis::{SabReader, SatBody, SatDocument};
use acadrust::entities::{Body, Region, Solid3D, Surface};
use cadkernel::brep::{self, Body as KernelBody};
use codec::entities::acis::{SabReader, SatBody, SatDocument};
use codec::entities::{Body, Region, Solid3D, Surface};
use kernel::brep::{self, Body as KernelBody};
use crate::scene::model::mesh_model::{MeshLodSet, MeshModel};
@@ -81,7 +81,7 @@ pub(crate) fn finalize_mesh(
verts: Vec<[f64; 3]>,
normals: Vec<[f32; 3]>,
indices: Vec<u32>,
triangle_material_handles: Vec<Option<acadrust::Handle>>,
triangle_material_handles: Vec<Option<codec::Handle>>,
triangle_colors: Vec<Option<[f32; 4]>>,
color: [f32; 4],
xform: Option<([f64; 9], [f64; 3], f64)>,
@@ -169,13 +169,13 @@ pub fn kernel_surface_body(surface: &Surface) -> Option<KernelBody> {
kernel_acis_body(&surface.acis_data)
}
pub(crate) fn kernel_acis_body(acis: &acadrust::entities::AcisData) -> Option<KernelBody> {
pub(crate) fn kernel_acis_body(acis: &codec::entities::AcisData) -> Option<KernelBody> {
let sat = parse_acis(
|| acis.parse(),
acis.is_binary,
&acis.sab_data,
)?;
let (mut bodies, loss) = cadkernel::acis::lift(&sat);
let (mut bodies, loss) = kernel::acis::lift(&sat);
if !loss.is_empty() || bodies.len() != 1 {
return None;
}
@@ -198,7 +198,7 @@ pub(crate) fn kernel_acis_body(acis: &acadrust::entities::AcisData) -> Option<Ke
fn remap_acis_material_bindings(
set: &mut MeshLodSet,
acis: &acadrust::entities::AcisData,
acis: &codec::entities::AcisData,
) {
for lod in &mut set.lods {
for handle in lod.triangle_material_handles.iter_mut().flatten() {
@@ -222,7 +222,7 @@ fn finish(
chordal_deflection: Option<f64>,
isolines: [usize; 2],
planar_isolines: bool,
acis: &acadrust::entities::AcisData,
acis: &codec::entities::AcisData,
) -> Option<MeshLodSet> {
let mut set = tessellate_acis(
&sat,
@@ -286,7 +286,7 @@ pub fn tessellate_body(
}
pub fn tessellate_surface(
surface: &acadrust::entities::Surface,
surface: &codec::entities::Surface,
color: [f32; 4],
facet_res: f64,
chordal_deflection: Option<f64>,
+36 -36
View File
@@ -5,7 +5,7 @@ use super::super::*;
/// layer is locked, so locked objects read as non-editable (they stay visible
/// and snappable). No-op for unlocked layers.
fn fade_if_locked(
document: &acadrust::CadDocument,
document: &codec::CadDocument,
e: &EntityType,
color: [f32; 4],
bg: [f32; 4],
@@ -43,8 +43,8 @@ pub(crate) struct BlockObjectOptions {
}
fn block_object_style(
document: &acadrust::CadDocument,
insert: &acadrust::entities::Insert,
document: &codec::CadDocument,
insert: &codec::entities::Insert,
active_viewport: Option<Handle>,
bg_color: [f32; 4],
) -> BlockObjectStyle {
@@ -61,7 +61,7 @@ fn block_object_style(
.layers
.get(&insert.common.layer)
.and_then(|layer| match &layer.color {
acadrust::types::Color::Index(index) => Some(*index),
codec::types::Color::Index(index) => Some(*index),
_ => None,
})
.unwrap_or(0);
@@ -84,8 +84,8 @@ fn block_object_style(
#[allow(clippy::too_many_arguments)]
pub(crate) fn expand_block_object(
document: &acadrust::CadDocument,
insert: &acadrust::entities::Insert,
document: &codec::CadDocument,
insert: &codec::entities::Insert,
owner: Handle,
selected: bool,
active_viewport: Option<Handle>,
@@ -208,10 +208,10 @@ pub(crate) fn expand_block_object(
/// `None` when any link is missing (DXF files, older DWGs) — the caller then
/// falls back to a geometric heuristic.
fn section_arrow_dir_from_views(
document: &acadrust::CadDocument,
s: &acadrust::entities::SectionSymbol,
document: &codec::CadDocument,
s: &codec::entities::SectionSymbol,
) -> Option<[f64; 2]> {
use acadrust::types::Handle as AHandle;
use codec::types::Handle as AHandle;
if s.view_rep_handle.is_null() {
return None;
}
@@ -289,9 +289,9 @@ fn section_arrow_dir_from_views(
/// ([`section_arrow_dir_from_views`]); only when that chain is unavailable
/// does it fall back to the 90°-CCW rotation of END-A→END-B.
fn section_symbol_wires(
document: &acadrust::CadDocument,
s: &acadrust::entities::SectionSymbol,
style: Option<&acadrust::entities::SectionViewStyle>,
document: &codec::CadDocument,
s: &codec::entities::SectionSymbol,
style: Option<&codec::entities::SectionViewStyle>,
h: Handle,
color: [f32; 4],
sel: bool,
@@ -342,7 +342,7 @@ fn section_symbol_wires(
let arrow_kind = match style {
Some(st) if st.arrow_start_handle != 0 => arrow_from_block(
document,
acadrust::types::Handle::from(st.arrow_start_handle),
codec::types::Handle::from(st.arrow_start_handle),
arrow_size as f32,
),
_ => ArrowKind::Triangle {
@@ -480,7 +480,7 @@ fn section_symbol_wires(
/// then re-color the returned wires with the dimension's resolved text colour
/// (so DIMCLRT / DIMSTYLE colours win over the synthetic Text's defaults).
pub(crate) fn tessellate_entity_dim_text(
document: &acadrust::CadDocument,
document: &codec::CadDocument,
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
bg_color: [f32; 4],
@@ -515,7 +515,7 @@ pub(crate) fn tessellate_entity_dim_text(
wires
}
pub(crate) fn tessellate_entity(
document: &acadrust::CadDocument,
document: &codec::CadDocument,
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
bg_color: [f32; 4],
@@ -556,7 +556,7 @@ pub(crate) fn tessellate_entity(
wires
}
fn tessellate_entity_inner(
document: &acadrust::CadDocument,
document: &codec::CadDocument,
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
bg_color: [f32; 4],
@@ -769,7 +769,7 @@ fn tessellate_entity_inner(
.as_deref()
.map(std::borrow::Cow::Borrowed),
EntityType::Extended(entity) => match &entity.data {
acadrust::entities::ExtendedEntityData::Proxy(proxy) => {
codec::entities::ExtendedEntityData::Proxy(proxy) => {
Some(std::borrow::Cow::Owned(proxy.graphics.data()))
}
_ => None,
@@ -788,7 +788,7 @@ fn tessellate_entity_inner(
match pc {
ProxyColor::Aci(a) => (
view::render::adapt_to_bg(
convert::tess_util::aci_to_rgba(&acadrust::types::Color::Index(a)),
convert::tess_util::aci_to_rgba(&codec::types::Color::Index(a)),
bg_color,
),
a,
@@ -816,7 +816,7 @@ fn tessellate_entity_inner(
for ((pcolor, plw), pts64) in groups {
let (col, w_aci) = resolve(pcolor);
let lw_px = if plw >= 0 {
view::render::lineweight_to_px(&acadrust::types::LineWeight::Value(plw))
view::render::lineweight_to_px(&codec::types::LineWeight::Value(plw))
} else {
line_weight_px
};
@@ -1697,7 +1697,7 @@ pub(crate) fn wire_points_aabb(w: &WireModel) -> [f32; 4] {
/// Assign `entity_box` as `w`'s cullable box, widened to cover the wire's
/// actual tessellated geometry and pick-only geometry.
///
/// `entity_aabb`'s box comes from acadrust's `bounding_box()`, which for a
/// `entity_aabb`'s box comes from opencadcodec's `bounding_box()`, which for a
/// polyline is often the box of its stored vertices — it may know nothing about
/// bulge arcs between them, the band a width paints around them, or the wall a
/// thickness extrudes. Hit-testing rejects on this box before it looks at the
@@ -1734,29 +1734,29 @@ pub(crate) fn set_wire_aabb(w: &mut WireModel, entity_box: [f32; 4]) {
w.aabb = out;
}
pub(crate) fn entity_bounds(e: &acadrust::EntityType) -> ([f64; 3], [f64; 3]) {
if let acadrust::EntityType::Region(region) = e {
pub(crate) fn entity_bounds(e: &codec::EntityType) -> ([f64; 3], [f64; 3]) {
if let codec::EntityType::Region(region) = e {
if region.wires.is_empty() {
if let Some(bounds) = super::solid3d_tess::kernel_region_body(region)
.and_then(|body| cadkernel::brep::body_bounds(&body))
.and_then(|body| kernel::brep::body_bounds(&body))
{
return (bounds.min, bounds.max);
}
}
}
if let acadrust::EntityType::Line(line) = e {
if let Some(association) = acadrust::entities::CenterMarkAssociation::read(
if let codec::EntityType::Line(line) = e {
if let Some(association) = codec::entities::CenterMarkAssociation::read(
&line.common.extended_data,
) {
return crate::scene::centermark::mark_bounds(&association);
}
}
if let acadrust::EntityType::Solid(solid) = e {
if let codec::EntityType::Solid(solid) = e {
if let Some(bounds) = crate::entities::solid::wcs_bounds(solid) {
return (bounds.min, bounds.max);
}
}
if let acadrust::EntityType::Spline(spline) = e {
if let codec::EntityType::Spline(spline) = e {
if let Some(bounds) = crate::entities::spline::fit_geometry_bounds(spline) {
return (bounds.min, bounds.max);
}
@@ -1771,10 +1771,10 @@ pub(crate) fn entity_bounds(e: &acadrust::EntityType) -> ([f64; 3], [f64; 3]) {
/// [`entity_bounds`] with the document, for entities whose extent is not
/// stored on the entity: an underlay spans its page (or its clip).
pub(crate) fn entity_bounds_in(
document: &acadrust::CadDocument,
e: &acadrust::EntityType,
document: &codec::CadDocument,
e: &codec::EntityType,
) -> ([f64; 3], [f64; 3]) {
if let acadrust::EntityType::Underlay(underlay) = e {
if let codec::EntityType::Underlay(underlay) = e {
if let Some(bounds) = crate::entities::underlay::world_bounds(underlay, document) {
return bounds;
}
@@ -1783,8 +1783,8 @@ pub(crate) fn entity_bounds_in(
}
/// [`entity_aabb`] with the document (see [`entity_bounds_in`]).
pub(crate) fn entity_aabb_in(document: &acadrust::CadDocument, e: &acadrust::EntityType) -> [f32; 4] {
if let acadrust::EntityType::Underlay(underlay) = e {
pub(crate) fn entity_aabb_in(document: &codec::CadDocument, e: &codec::EntityType) -> [f32; 4] {
if let codec::EntityType::Underlay(underlay) = e {
if let Some((min, max)) = crate::entities::underlay::world_bounds(underlay, document) {
return [min[0] as f32, min[1] as f32, max[0] as f32, max[1] as f32];
}
@@ -1792,7 +1792,7 @@ pub(crate) fn entity_aabb_in(document: &acadrust::CadDocument, e: &acadrust::Ent
entity_aabb(e)
}
pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
pub(crate) fn entity_aabb(e: &codec::EntityType) -> [f32; 4] {
let (min, max) = entity_bounds(e);
let min_x = min[0] as f32;
let min_y = min[1] as f32;
@@ -1814,7 +1814,7 @@ pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
/// (which `entity_aabb` collapses to `UNBOUNDED_AABB`). Quadtree
/// indexing uses this so changing `world_offset` doesn't invalidate
/// the index.
pub(crate) fn entity_world_aabb_f64(e: &acadrust::EntityType) -> Option<[f64; 4]> {
pub(crate) fn entity_world_aabb_f64(e: &codec::EntityType) -> Option<[f64; 4]> {
let (min, max) = entity_bounds(e);
let (xmin, ymin, xmax, ymax) = (min[0], min[1], max[0], max[1]);
if xmin == xmax && ymin == ymax {
@@ -1830,8 +1830,8 @@ pub(crate) fn entity_world_aabb_f64(e: &acadrust::EntityType) -> Option<[f64; 4]
/// `Viewport` are sized only after extra transformation; tessellation
/// already handles them via dedicated code paths. `Block`/`BlockEnd`
/// are block-defn sentinels with no geometry.
pub(crate) fn is_unindexable_entity(e: &acadrust::EntityType) -> bool {
use acadrust::EntityType as E;
pub(crate) fn is_unindexable_entity(e: &codec::EntityType) -> bool {
use codec::EntityType as E;
matches!(
e,
E::Insert(_) | E::Viewport(_) | E::Block(_) | E::BlockEnd(_)
+2 -2
View File
@@ -3,7 +3,7 @@
//
// Cross-entity rendering helpers live here.
use acadrust::types::Color as AcadColor;
use codec::types::Color as AcadColor;
use glam::Vec3;
use crate::scene::model::wire_model::{SnapHint, TangentGeom, WireModel};
@@ -28,7 +28,7 @@ pub type FallbackGeometry = (
// ── Colour helper ──────────────────────────────────────────────────────────
/// Convert an acadrust Color (ACI index or true-color) to a GPU RGBA value.
/// Convert an opencadcodec Color (ACI index or true-color) to a GPU RGBA value.
pub fn aci_to_rgba(color: &AcadColor) -> [f32; 4] {
if let Some((r, g, b)) = color.rgb() {
[r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0]
+23 -23
View File
@@ -1,4 +1,4 @@
// Tessellation — convert acadrust EntityType to GPU-ready WireModel or MeshModel.
// Tessellation — convert opencadcodec EntityType to GPU-ready WireModel or MeshModel.
//
// Flow:
// EntityType
@@ -14,8 +14,8 @@
// are tessellated by the FallbackTess fallback_geometry() path.
use crate::entities::leader::LeaderTess;
use acadrust::types::Color as AcadColor;
use acadrust::{CadDocument, EntityType, Handle};
use codec::types::Color as AcadColor;
use codec::{CadDocument, EntityType, Handle};
use glam::Vec3;
use crate::scene::convert::acad_to_render::{convert, RenderObject};
@@ -80,7 +80,7 @@ fn oriented_text_corners(
fn oriented_mtext_corner_groups(
verts: &[crate::scene::pipeline::text_gpu::TextVertex],
text: &acadrust::MText,
text: &codec::MText,
rotation: f64,
pad: f64,
annotation_scale: f64,
@@ -101,12 +101,12 @@ fn oriented_mtext_corner_groups(
let gutter = columns.gutter.max(0.0) * annotation_scale;
let total_width = width * count as f64 + gutter * count.saturating_sub(1) as f64;
let anchor = match text.attachment_point {
acadrust::entities::mtext::AttachmentPoint::TopCenter
| acadrust::entities::mtext::AttachmentPoint::MiddleCenter
| acadrust::entities::mtext::AttachmentPoint::BottomCenter => 0.5,
acadrust::entities::mtext::AttachmentPoint::TopRight
| acadrust::entities::mtext::AttachmentPoint::MiddleRight
| acadrust::entities::mtext::AttachmentPoint::BottomRight => 1.0,
codec::entities::mtext::AttachmentPoint::TopCenter
| codec::entities::mtext::AttachmentPoint::MiddleCenter
| codec::entities::mtext::AttachmentPoint::BottomCenter => 0.5,
codec::entities::mtext::AttachmentPoint::TopRight
| codec::entities::mtext::AttachmentPoint::MiddleRight
| codec::entities::mtext::AttachmentPoint::BottomRight => 1.0,
_ => 0.0,
};
let block_left = -anchor * total_width;
@@ -229,7 +229,7 @@ fn polyline_segment_widths(entity: &EntityType) -> Vec<(f32, f32)> {
}
EntityType::Polyline2D(p) => {
let filtered = crate::entities::polyline::drawn_vertices2d(p);
let verts: &[acadrust::entities::Vertex2D] =
let verts: &[codec::entities::Vertex2D] =
filtered.as_deref().unwrap_or(&p.vertices);
let count = verts.len();
let seg_count = if p.is_closed() {
@@ -2419,7 +2419,7 @@ pub(crate) enum ArrowKind {
pub(crate) fn arrow_from_block(
doc: &CadDocument,
handle: acadrust::types::Handle,
handle: codec::types::Handle,
dimasz: f32,
) -> ArrowKind {
arrow_from_block_with_deferred_hatch(doc, handle, dimasz, false)
@@ -2427,7 +2427,7 @@ pub(crate) fn arrow_from_block(
pub(crate) fn arrow_from_block_with_deferred_hatch(
doc: &CadDocument,
handle: acadrust::types::Handle,
handle: codec::types::Handle,
dimasz: f32,
defer_hatch: bool,
) -> ArrowKind {
@@ -2534,7 +2534,7 @@ fn builtin_arrow_from_block_name(name: &str, dimasz: f32) -> Option<ArrowKind> {
fn custom_arrow_from_block(
doc: &CadDocument,
record: &acadrust::tables::BlockRecord,
record: &codec::tables::BlockRecord,
dimasz: f32,
defer_hatch: bool,
) -> Option<ArrowKind> {
@@ -2560,7 +2560,7 @@ fn custom_arrow_from_block(
doc,
record.handle,
crate::scene::render_graph::BlockRole::ArrowHead,
acadrust::types::Vector3::ZERO,
codec::types::Vector3::ZERO,
)?;
let mut lines = Vec::new();
let mut fill = Vec::new();
@@ -2612,7 +2612,7 @@ fn append_custom_arrow_leaf(
EntityType::Hatch(hatch) => {
append_custom_hatch_geometry(
hatch,
acadrust::types::Vector3::ZERO,
codec::types::Vector3::ZERO,
lines,
fill,
);
@@ -2640,21 +2640,21 @@ fn append_custom_arrow_leaf(
append_custom_wire_points(
&wire.points,
&wire.points_low,
acadrust::types::Vector3::ZERO,
codec::types::Vector3::ZERO,
lines,
);
append_custom_fill_points(
&wire.fill_tris,
&wire.fill_tris_low,
acadrust::types::Vector3::ZERO,
codec::types::Vector3::ZERO,
fill,
);
}
}
fn append_custom_hatch_geometry(
hatch: &acadrust::entities::Hatch,
base: acadrust::types::Vector3,
hatch: &codec::entities::Hatch,
base: codec::types::Vector3,
lines: &mut Vec<[f32; 3]>,
fill: &mut Vec<[f32; 3]>,
) {
@@ -2742,7 +2742,7 @@ fn append_custom_hatch_geometry(
fn append_custom_wire_points(
points: &[[f32; 3]],
points_low: &[[f32; 3]],
base: acadrust::types::Vector3,
base: codec::types::Vector3,
out: &mut Vec<[f32; 3]>,
) {
if points.is_empty() {
@@ -2770,7 +2770,7 @@ fn append_custom_wire_points(
fn append_custom_fill_points(
points: &[[f32; 3]],
points_low: &[[f32; 3]],
base: acadrust::types::Vector3,
base: codec::types::Vector3,
out: &mut Vec<[f32; 3]>,
) {
for (index, point) in points.iter().enumerate() {
@@ -2800,7 +2800,7 @@ impl DimGeom {
}
/// Convert an acadrust `Color` to RGBA, falling back to `inherited` for
/// Convert an opencadcodec `Color` to RGBA, falling back to `inherited` for
/// `ByLayer` / `ByBlock` (assumes those are already resolved upstream).
pub(crate) fn color_or_inherit(c: &AcadColor, inherited: [f32; 4]) -> [f32; 4] {
match c.rgb() {