forked from 1b-agent/opencadstudio-upstream
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
56c04408d6
commit
f537aff75c
430 files changed
+9925
-8540
No files matched your search
+66
-66
@@ -1,7 +1,7 @@
|
||||
use acadrust::entities::{MLine, MLineFlags, MLineSegment};
|
||||
use acadrust::types::Vector3;
|
||||
use cadkernel::geom2d::{intersect::line_line, Vec2};
|
||||
use cadkernel::space::Plane;
|
||||
use codec::entities::{MLine, MLineFlags, MLineSegment};
|
||||
use codec::types::Vector3;
|
||||
use kernel::geom2d::{intersect::line_line, Vec2};
|
||||
use kernel::space::Plane;
|
||||
|
||||
use crate::command::EntityTransform;
|
||||
use crate::entities::common::{edit_prop as edit, ro_prop, square_grip};
|
||||
@@ -14,7 +14,7 @@ use crate::t;
|
||||
/// One styled line or cap of a multiline.
|
||||
pub struct MLineLine {
|
||||
pub points: Vec<[f64; 3]>,
|
||||
pub color: acadrust::types::Color,
|
||||
pub color: codec::types::Color,
|
||||
pub linetype: String,
|
||||
}
|
||||
|
||||
@@ -38,19 +38,19 @@ pub(crate) fn rebuild_mline_geometry(mline: &mut MLine) -> bool {
|
||||
let axis = points
|
||||
.windows(2)
|
||||
.find_map(|pair| {
|
||||
(cadkernel::space::Vec3::from(pair[1]) - cadkernel::space::Vec3::from(pair[0]))
|
||||
(kernel::space::Vec3::from(pair[1]) - kernel::space::Vec3::from(pair[0]))
|
||||
.normalize()
|
||||
.map(cadkernel::space::Vec3::to_array)
|
||||
.map(kernel::space::Vec3::to_array)
|
||||
})
|
||||
.or_else(|| {
|
||||
mline.is_closed()
|
||||
.then(|| {
|
||||
(cadkernel::space::Vec3::from(points[0])
|
||||
- cadkernel::space::Vec3::from(points[count - 1]))
|
||||
(kernel::space::Vec3::from(points[0])
|
||||
- kernel::space::Vec3::from(points[count - 1]))
|
||||
.normalize()
|
||||
})
|
||||
.flatten()
|
||||
.map(cadkernel::space::Vec3::to_array)
|
||||
.map(kernel::space::Vec3::to_array)
|
||||
});
|
||||
let Some(plane) = axis.and_then(|axis| {
|
||||
Plane::orthonormal(
|
||||
@@ -130,7 +130,7 @@ pub(crate) fn rebuild_mline_geometry(mline: &mut MLine) -> bool {
|
||||
|
||||
fn adjusted_mline_endpoint(
|
||||
mline: &MLine,
|
||||
style: &acadrust::objects::MLineStyle,
|
||||
style: &codec::objects::MLineStyle,
|
||||
vertex: usize,
|
||||
point: [f64; 3],
|
||||
) -> [f64; 3] {
|
||||
@@ -139,7 +139,7 @@ fn adjusted_mline_endpoint(
|
||||
} else {
|
||||
style.end_angle
|
||||
};
|
||||
let Some(tangent) = cadkernel::space::Vec3::new(
|
||||
let Some(tangent) = kernel::space::Vec3::new(
|
||||
mline.vertices[vertex].direction.x,
|
||||
mline.vertices[vertex].direction.y,
|
||||
mline.vertices[vertex].direction.z,
|
||||
@@ -149,23 +149,23 @@ fn adjusted_mline_endpoint(
|
||||
return point;
|
||||
};
|
||||
let Some(normal) =
|
||||
cadkernel::space::Vec3::new(mline.normal.x, mline.normal.y, mline.normal.z).normalize()
|
||||
kernel::space::Vec3::new(mline.normal.x, mline.normal.y, mline.normal.z).normalize()
|
||||
else {
|
||||
return point;
|
||||
};
|
||||
let Some(transverse) = normal.cross(tangent).normalize() else {
|
||||
return point;
|
||||
};
|
||||
let base = cadkernel::space::Vec3::new(
|
||||
let base = kernel::space::Vec3::new(
|
||||
mline.vertices[vertex].position.x,
|
||||
mline.vertices[vertex].position.y,
|
||||
mline.vertices[vertex].position.z,
|
||||
);
|
||||
let current = cadkernel::space::Vec3::from(point);
|
||||
let current = kernel::space::Vec3::from(point);
|
||||
let tangent = if angle.tan().abs() > 1.0e-9 {
|
||||
tangent * ((current - base).dot(transverse) / angle.tan())
|
||||
} else {
|
||||
cadkernel::space::Vec3::ZERO
|
||||
kernel::space::Vec3::ZERO
|
||||
};
|
||||
(current + tangent).to_array()
|
||||
}
|
||||
@@ -344,7 +344,7 @@ fn mline_element_endpoints(
|
||||
mline: &MLine,
|
||||
vertex: usize,
|
||||
element: usize,
|
||||
) -> Option<(cadkernel::space::Vec3, cadkernel::space::Vec3)> {
|
||||
) -> Option<(kernel::space::Vec3, kernel::space::Vec3)> {
|
||||
let next = if vertex + 1 < mline.vertices.len() {
|
||||
vertex + 1
|
||||
} else if mline.is_closed() {
|
||||
@@ -355,12 +355,12 @@ fn mline_element_endpoints(
|
||||
let point = |index: usize| {
|
||||
let vertex = mline.vertices.get(index)?;
|
||||
let offset = vertex.segments.get(element)?.parameters.first().copied()?;
|
||||
let position = cadkernel::space::Vec3::new(
|
||||
let position = kernel::space::Vec3::new(
|
||||
vertex.position.x,
|
||||
vertex.position.y,
|
||||
vertex.position.z,
|
||||
);
|
||||
let miter = cadkernel::space::Vec3::new(vertex.miter.x, vertex.miter.y, vertex.miter.z);
|
||||
let miter = kernel::space::Vec3::new(vertex.miter.x, vertex.miter.y, vertex.miter.z);
|
||||
Some(position + miter * offset)
|
||||
};
|
||||
Some((point(vertex)?, point(next)?))
|
||||
@@ -425,7 +425,7 @@ fn restore_shifted_mline_segment(
|
||||
pub(crate) fn normalize_scripted_mline(
|
||||
old: Option<&MLine>,
|
||||
new: &mut MLine,
|
||||
document: &acadrust::CadDocument,
|
||||
document: &codec::CadDocument,
|
||||
) -> Result<(), String> {
|
||||
let style = resolved_mline_style(new, document)
|
||||
.ok_or_else(|| format!("MLine style {:?} does not exist", new.style_name))?;
|
||||
@@ -470,9 +470,9 @@ pub(crate) fn normalize_scripted_mline(
|
||||
/// Resolve a multiline into styled parallel lines in WCS.
|
||||
pub fn resolved_mline_style<'a>(
|
||||
m: &MLine,
|
||||
document: &'a acadrust::CadDocument,
|
||||
) -> Option<&'a acadrust::objects::MLineStyle> {
|
||||
use acadrust::objects::ObjectType;
|
||||
document: &'a codec::CadDocument,
|
||||
) -> Option<&'a codec::objects::MLineStyle> {
|
||||
use codec::objects::ObjectType;
|
||||
|
||||
m.style_handle
|
||||
.and_then(|handle| match document.objects.get(&handle) {
|
||||
@@ -491,23 +491,23 @@ pub fn resolved_mline_style<'a>(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mline_lines(m: &MLine, document: &acadrust::CadDocument) -> Vec<MLineLine> {
|
||||
pub fn mline_lines(m: &MLine, document: &codec::CadDocument) -> Vec<MLineLine> {
|
||||
mline_lines_resolved(m, resolved_mline_style(m, document))
|
||||
}
|
||||
|
||||
pub fn mline_lines_with_style(
|
||||
m: &MLine,
|
||||
style: &acadrust::objects::MLineStyle,
|
||||
style: &codec::objects::MLineStyle,
|
||||
) -> Vec<MLineLine> {
|
||||
mline_lines_resolved(m, Some(style))
|
||||
}
|
||||
|
||||
fn mline_lines_resolved(
|
||||
m: &MLine,
|
||||
style: Option<&acadrust::objects::MLineStyle>,
|
||||
style: Option<&codec::objects::MLineStyle>,
|
||||
) -> Vec<MLineLine> {
|
||||
use acadrust::entities::{MLineFlags, MLineJustification};
|
||||
use acadrust::types::Color;
|
||||
use codec::entities::{MLineFlags, MLineJustification};
|
||||
use codec::types::Color;
|
||||
|
||||
if m.vertices.is_empty() {
|
||||
return Vec::new();
|
||||
@@ -553,8 +553,8 @@ fn mline_lines_resolved(
|
||||
};
|
||||
let off_pt = |vi: usize, d: f64| -> [f64; 3] {
|
||||
let v = &m.vertices[vi];
|
||||
(cadkernel::space::Vec3::new(v.position.x, v.position.y, v.position.z)
|
||||
+ cadkernel::space::Vec3::new(v.miter.x, v.miter.y, v.miter.z) * d)
|
||||
(kernel::space::Vec3::new(v.position.x, v.position.y, v.position.z)
|
||||
+ kernel::space::Vec3::new(v.miter.x, v.miter.y, v.miter.z) * d)
|
||||
.to_array()
|
||||
};
|
||||
let endpoint_pt = |vi: usize, ei: usize| -> [f64; 3] {
|
||||
@@ -587,8 +587,8 @@ fn mline_lines_resolved(
|
||||
} else {
|
||||
off_pt(wi, elem_off(wi, ei))
|
||||
};
|
||||
let a = cadkernel::space::Vec3::from(a);
|
||||
let b = cadkernel::space::Vec3::from(b);
|
||||
let a = kernel::space::Vec3::from(a);
|
||||
let b = kernel::space::Vec3::from(b);
|
||||
let segment = b - a;
|
||||
let len = segment.length();
|
||||
let Some(direction) = segment.normalize() else {
|
||||
@@ -735,33 +735,33 @@ fn semicircle_cap(
|
||||
direction: [f64; 3],
|
||||
start: bool,
|
||||
) -> Vec<[f64; 3]> {
|
||||
let first = cadkernel::space::Vec3::from(first);
|
||||
let second = cadkernel::space::Vec3::from(second);
|
||||
let first = kernel::space::Vec3::from(first);
|
||||
let second = kernel::space::Vec3::from(second);
|
||||
let center = (first + second) * 0.5;
|
||||
let transverse = (first - second) * 0.5;
|
||||
let radius = transverse.length();
|
||||
let Some(x_axis) = transverse.normalize() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Some(direction) = cadkernel::space::Vec3::from(direction).normalize() else {
|
||||
let Some(direction) = kernel::space::Vec3::from(direction).normalize() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let y_axis = if start { -direction } else { direction };
|
||||
cadkernel::space::PlanarCurve::new(
|
||||
kernel::space::PlanarCurve::new(
|
||||
Plane::from_axes(center.to_array(), x_axis.to_array(), y_axis.to_array()),
|
||||
cadkernel::geom2d::Curve::Arc(cadkernel::geom2d::Arc {
|
||||
kernel::geom2d::Curve::Arc(kernel::geom2d::Arc {
|
||||
centre: [0.0, 0.0],
|
||||
radius,
|
||||
start_angle: 0.0,
|
||||
end_angle: std::f64::consts::PI,
|
||||
}),
|
||||
)
|
||||
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
||||
.tessellate_angle(kernel::tessellation::DEFAULT_ANGLE)
|
||||
}
|
||||
|
||||
pub fn mline_fill_triangles_with_style(
|
||||
m: &MLine,
|
||||
style: &acadrust::objects::MLineStyle,
|
||||
style: &codec::objects::MLineStyle,
|
||||
) -> Vec<[f64; 3]> {
|
||||
if !style.flags.fill_on || m.vertices.len() < 2 || style.elements.len() < 2 {
|
||||
return Vec::new();
|
||||
@@ -795,9 +795,9 @@ pub fn mline_fill_triangles_with_style(
|
||||
.map(|element| element.offset)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
let shift = match m.justification {
|
||||
acadrust::entities::MLineJustification::Top => -maximum,
|
||||
acadrust::entities::MLineJustification::Zero => 0.0,
|
||||
acadrust::entities::MLineJustification::Bottom => -minimum,
|
||||
codec::entities::MLineJustification::Top => -maximum,
|
||||
codec::entities::MLineJustification::Zero => 0.0,
|
||||
codec::entities::MLineJustification::Bottom => -minimum,
|
||||
};
|
||||
let offset_point = |vertex: usize, element: usize, endpoint: bool| -> [f64; 3] {
|
||||
let item = &m.vertices[vertex];
|
||||
@@ -807,11 +807,11 @@ pub fn mline_fill_triangles_with_style(
|
||||
.and_then(|segment| segment.parameters.first())
|
||||
.copied()
|
||||
.unwrap_or((style.elements[element].offset + shift) * m.scale_factor);
|
||||
let point = (cadkernel::space::Vec3::new(
|
||||
let point = (kernel::space::Vec3::new(
|
||||
item.position.x,
|
||||
item.position.y,
|
||||
item.position.z,
|
||||
) + cadkernel::space::Vec3::new(item.miter.x, item.miter.y, item.miter.z) * distance)
|
||||
) + kernel::space::Vec3::new(item.miter.x, item.miter.y, item.miter.z) * distance)
|
||||
.to_array();
|
||||
if endpoint {
|
||||
adjusted_mline_endpoint(m, style, vertex, point)
|
||||
@@ -830,18 +830,18 @@ pub fn mline_fill_triangles_with_style(
|
||||
let next = (vertex + 1) % m.vertices.len();
|
||||
let start_endpoint = !closed && vertex == 0;
|
||||
let end_endpoint = !closed && next + 1 == m.vertices.len();
|
||||
let low_start = cadkernel::space::Vec3::from(offset_point(
|
||||
let low_start = kernel::space::Vec3::from(offset_point(
|
||||
vertex,
|
||||
low_index,
|
||||
start_endpoint,
|
||||
));
|
||||
let low_end = cadkernel::space::Vec3::from(offset_point(next, low_index, end_endpoint));
|
||||
let high_start = cadkernel::space::Vec3::from(offset_point(
|
||||
let low_end = kernel::space::Vec3::from(offset_point(next, low_index, end_endpoint));
|
||||
let high_start = kernel::space::Vec3::from(offset_point(
|
||||
vertex,
|
||||
high_index,
|
||||
start_endpoint,
|
||||
));
|
||||
let high_end = cadkernel::space::Vec3::from(offset_point(next, high_index, end_endpoint));
|
||||
let high_end = kernel::space::Vec3::from(offset_point(next, high_index, end_endpoint));
|
||||
let low_length = low_start.distance(low_end);
|
||||
let high_length = high_start.distance(high_end);
|
||||
if low_length <= 1.0e-12 || high_length <= 1.0e-12 {
|
||||
@@ -879,7 +879,7 @@ pub fn mline_fill_triangles_with_style(
|
||||
}
|
||||
|
||||
impl RenderConvertible for MLine {
|
||||
fn to_render(&self, document: &acadrust::CadDocument) -> Option<RenderEntity> {
|
||||
fn to_render(&self, document: &codec::CadDocument) -> Option<RenderEntity> {
|
||||
if self.vertices.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -941,13 +941,13 @@ impl Grippable for MLine {
|
||||
return;
|
||||
};
|
||||
let position = match apply {
|
||||
GripApply::Translate(delta) => acadrust::types::Vector3::new(
|
||||
GripApply::Translate(delta) => codec::types::Vector3::new(
|
||||
vertex.position.x + delta.x as f64,
|
||||
vertex.position.y + delta.y as f64,
|
||||
vertex.position.z + delta.z as f64,
|
||||
),
|
||||
GripApply::Absolute(point) => {
|
||||
acadrust::types::Vector3::new(point.x as f64, point.y as f64, point.z as f64)
|
||||
codec::types::Vector3::new(point.x as f64, point.y as f64, point.z as f64)
|
||||
}
|
||||
};
|
||||
let count = self.vertices.len();
|
||||
@@ -1039,7 +1039,7 @@ impl Grippable for MLine {
|
||||
new_v.position.x = (v0.position.x + v1.position.x) * 0.5;
|
||||
new_v.position.y = (v0.position.y + v1.position.y) * 0.5;
|
||||
new_v.position.z = (v0.position.z + v1.position.z) * 0.5;
|
||||
let point = cadkernel::space::Vec3::new(
|
||||
let point = kernel::space::Vec3::new(
|
||||
new_v.position.x,
|
||||
new_v.position.y,
|
||||
new_v.position.z,
|
||||
@@ -1233,9 +1233,9 @@ impl Grippable for MLine {
|
||||
impl PropertyEditable for MLine {
|
||||
fn geometry_properties(&self, _text_style_names: &[String]) -> Vec<PropSection> {
|
||||
let just_str = match self.justification {
|
||||
acadrust::entities::MLineJustification::Top => "Top",
|
||||
acadrust::entities::MLineJustification::Zero => "Zero",
|
||||
acadrust::entities::MLineJustification::Bottom => "Bottom",
|
||||
codec::entities::MLineJustification::Top => "Top",
|
||||
codec::entities::MLineJustification::Zero => "Zero",
|
||||
codec::entities::MLineJustification::Bottom => "Bottom",
|
||||
};
|
||||
vec![PropSection {
|
||||
title: t!("Misc").into_owned(),
|
||||
@@ -1261,13 +1261,13 @@ impl PropertyEditable for MLine {
|
||||
match field {
|
||||
"ml_closed" => {
|
||||
let closed = if value == "toggle" {
|
||||
!self.flags.contains(acadrust::entities::MLineFlags::CLOSED)
|
||||
!self.flags.contains(codec::entities::MLineFlags::CLOSED)
|
||||
} else {
|
||||
value == "true"
|
||||
};
|
||||
let offsets = mline_perpendicular_offsets(self);
|
||||
self.flags.set(
|
||||
acadrust::entities::MLineFlags::CLOSED,
|
||||
codec::entities::MLineFlags::CLOSED,
|
||||
closed && self.vertices.len() >= 3,
|
||||
);
|
||||
rebuild_mline_geometry(self);
|
||||
@@ -1276,9 +1276,9 @@ impl PropertyEditable for MLine {
|
||||
}
|
||||
"ml_justification" => {
|
||||
self.justification = match value {
|
||||
"Top" => acadrust::entities::MLineJustification::Top,
|
||||
"Bottom" => acadrust::entities::MLineJustification::Bottom,
|
||||
_ => acadrust::entities::MLineJustification::Zero,
|
||||
"Top" => codec::entities::MLineJustification::Top,
|
||||
"Bottom" => codec::entities::MLineJustification::Bottom,
|
||||
_ => codec::entities::MLineJustification::Zero,
|
||||
};
|
||||
return;
|
||||
}
|
||||
@@ -1329,16 +1329,16 @@ fn set_mline_scale(mline: &mut MLine, scale: f64) {
|
||||
|
||||
fn mline_vertex_factor(mline: &MLine, index: usize) -> f64 {
|
||||
let vertex = &mline.vertices[index];
|
||||
let normal = cadkernel::space::Vec3::new(mline.normal.x, mline.normal.y, mline.normal.z)
|
||||
let normal = kernel::space::Vec3::new(mline.normal.x, mline.normal.y, mline.normal.z)
|
||||
.normalize()
|
||||
.unwrap_or(cadkernel::space::Vec3::Z);
|
||||
.unwrap_or(kernel::space::Vec3::Z);
|
||||
let direction =
|
||||
cadkernel::space::Vec3::new(vertex.direction.x, vertex.direction.y, vertex.direction.z)
|
||||
kernel::space::Vec3::new(vertex.direction.x, vertex.direction.y, vertex.direction.z)
|
||||
.normalize()
|
||||
.unwrap_or(cadkernel::space::Vec3::X);
|
||||
let miter = cadkernel::space::Vec3::new(vertex.miter.x, vertex.miter.y, vertex.miter.z)
|
||||
.unwrap_or(kernel::space::Vec3::X);
|
||||
let miter = kernel::space::Vec3::new(vertex.miter.x, vertex.miter.y, vertex.miter.z)
|
||||
.normalize()
|
||||
.unwrap_or(cadkernel::space::Vec3::Y);
|
||||
.unwrap_or(kernel::space::Vec3::Y);
|
||||
miter.dot(normal.cross(direction)).abs().max(1.0e-9)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user