forked from 1b-agent/opencadstudio-upstream
Convert fitted polylines through the spline Object option
This commit is contained in:
1 parent
bfac3f130c
commit
8e5f0955d2
2 files changed
+78
-5
No files matched your search
@@ -881,7 +881,7 @@ impl OpenCADStudio {
|
|||||||
SplineCommand::control_vertices()
|
SplineCommand::control_vertices()
|
||||||
} else {
|
} else {
|
||||||
SplineCommand::new()
|
SplineCommand::new()
|
||||||
};
|
}.with_document(&self.tabs[i].scene.document);
|
||||||
self.command_line.push_info(&new_cmd.prompt());
|
self.command_line.push_info(&new_cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
use crate::t;
|
use crate::t;
|
||||||
use acadrust::types::Vector3;
|
use acadrust::types::Vector3;
|
||||||
use acadrust::{EntityType, Spline};
|
use acadrust::{CadDocument, EntityType, Handle, Spline};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::command::{CadCommand, CmdResult};
|
use crate::command::{CadCommand, CmdResult};
|
||||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||||
@@ -31,6 +32,9 @@ pub struct SplineCommand {
|
|||||||
knot_parameterization: i32,
|
knot_parameterization: i32,
|
||||||
begin_tangent: Vector3,
|
begin_tangent: Vector3,
|
||||||
end_tangent: Vector3,
|
end_tangent: Vector3,
|
||||||
|
choosing_objects: bool,
|
||||||
|
convertible: HashMap<Handle, Spline>,
|
||||||
|
selected_objects: Vec<Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SplineCommand {
|
impl SplineCommand {
|
||||||
@@ -44,6 +48,9 @@ impl SplineCommand {
|
|||||||
knot_parameterization: 0,
|
knot_parameterization: 0,
|
||||||
begin_tangent: Vector3::ZERO,
|
begin_tangent: Vector3::ZERO,
|
||||||
end_tangent: Vector3::ZERO,
|
end_tangent: Vector3::ZERO,
|
||||||
|
choosing_objects: false,
|
||||||
|
convertible: HashMap::new(),
|
||||||
|
selected_objects: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +61,13 @@ impl SplineCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_document(mut self, document: &CadDocument) -> Self {
|
||||||
|
self.convertible = document.entities().filter_map(|entity| {
|
||||||
|
spline_from_polyline(entity).map(|spline| (entity.common().handle, spline))
|
||||||
|
}).collect();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn build(&self, closed: bool) -> Option<EntityType> {
|
fn build(&self, closed: bool) -> Option<EntityType> {
|
||||||
if self.pts.len() < 2 {
|
if self.pts.len() < 2 {
|
||||||
return None;
|
return None;
|
||||||
@@ -70,6 +84,45 @@ impl SplineCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn control_spline(points: &[[f64; 3]], degree: usize, closed: bool) -> Option<Spline> {
|
||||||
|
let curve = cadkernel::space::NurbsCurve3::from_control_polygon(degree, points, closed)?;
|
||||||
|
let mut spline = Spline {
|
||||||
|
degree: curve.degree() as i32,
|
||||||
|
control_points: curve.control_points().iter().map(|p| Vector3::new(p[0], p[1], p[2])).collect(),
|
||||||
|
knots: curve.knots().to_vec(),
|
||||||
|
weights: curve.weights().to_vec(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
spline.flags.closed = closed;
|
||||||
|
spline.flags.periodic = closed;
|
||||||
|
spline.flags.planar = crate::entities::curve::spline_is_planar(&spline);
|
||||||
|
Some(spline)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spline_from_polyline(entity: &EntityType) -> Option<Spline> {
|
||||||
|
let (degree, points, closed, normal) = match entity {
|
||||||
|
EntityType::Polyline2D(poly) if poly.flags.is_spline_fit() => {
|
||||||
|
let degree = match poly.smooth_surface as i16 { 5 => 2, 6 => 3, _ => return None };
|
||||||
|
let plane = crate::entities::curve::ocs_plane(poly.normal, poly.elevation);
|
||||||
|
let controls: Vec<_> = poly.vertices.iter().filter(|vertex| vertex.flags.bits() & 16 != 0)
|
||||||
|
.map(|vertex| plane.point_at([vertex.location.x, vertex.location.y])).collect();
|
||||||
|
(degree, controls, poly.is_closed(), poly.normal)
|
||||||
|
}
|
||||||
|
EntityType::Polyline3D(poly) if poly.flags.spline_fit => {
|
||||||
|
let degree = match poly.smooth_type as i16 { 5 => 2, 6 => 3, _ => return None };
|
||||||
|
let controls: Vec<_> = poly.vertices.iter().filter(|vertex| vertex.flags & 16 != 0)
|
||||||
|
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z]).collect();
|
||||||
|
(degree, controls, poly.is_closed(), poly.normal)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let mut spline = control_spline(&points, degree, closed)?;
|
||||||
|
spline.normal = normal;
|
||||||
|
spline.common = entity.common().clone();
|
||||||
|
spline.common.handle = Handle::NULL;
|
||||||
|
Some(spline)
|
||||||
|
}
|
||||||
|
|
||||||
/// Store the chosen construction method directly in the persistent spline.
|
/// Store the chosen construction method directly in the persistent spline.
|
||||||
fn make_spline(pts: &[DVec3], closed: bool, control_vertices: bool) -> Spline {
|
fn make_spline(pts: &[DVec3], closed: bool, control_vertices: bool) -> Spline {
|
||||||
let mut points: Vec<Vector3> = pts.iter().map(|p| Vector3::new(p.x, p.y, p.z)).collect();
|
let mut points: Vec<Vector3> = pts.iter().map(|p| Vector3::new(p.x, p.y, p.z)).collect();
|
||||||
@@ -141,6 +194,7 @@ impl CadCommand for SplineCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prompt(&self) -> String {
|
fn prompt(&self) -> String {
|
||||||
|
if self.choosing_objects { return t!("Select spline-fit polylines:").to_string(); }
|
||||||
if self.choosing_method {
|
if self.choosing_method {
|
||||||
"SPLINE Choose creation method [Fit/Control vertices]:".into()
|
"SPLINE Choose creation method [Fit/Control vertices]:".into()
|
||||||
} else if self.choosing_knots {
|
} else if self.choosing_knots {
|
||||||
@@ -159,6 +213,7 @@ impl CadCommand for SplineCommand {
|
|||||||
|
|
||||||
fn options(&self) -> Vec<crate::command::CmdOption> {
|
fn options(&self) -> Vec<crate::command::CmdOption> {
|
||||||
use crate::command::CmdOption;
|
use crate::command::CmdOption;
|
||||||
|
if self.choosing_objects { return Vec::new(); }
|
||||||
if self.choosing_method {
|
if self.choosing_method {
|
||||||
return vec![
|
return vec![
|
||||||
CmdOption::new("Fit", "FIT"),
|
CmdOption::new("Fit", "FIT"),
|
||||||
@@ -170,7 +225,7 @@ impl CadCommand for SplineCommand {
|
|||||||
return vec![CmdOption::new("Chord", "CH"), CmdOption::new("Square root", "S"), CmdOption::new("Uniform", "U")];
|
return vec![CmdOption::new("Chord", "CH"), CmdOption::new("Square root", "S"), CmdOption::new("Uniform", "U")];
|
||||||
}
|
}
|
||||||
if self.pts.is_empty() {
|
if self.pts.is_empty() {
|
||||||
let mut options = vec![CmdOption::new(t!("Method").as_ref(), "M")];
|
let mut options = vec![CmdOption::new(t!("Method").as_ref(), "M"), CmdOption::new("Object", "O")];
|
||||||
if !self.control_vertices { options.push(CmdOption::new("Knots", "K")); }
|
if !self.control_vertices { options.push(CmdOption::new("Knots", "K")); }
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
@@ -184,7 +239,7 @@ impl CadCommand for SplineCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||||
if self.choosing_method || self.choosing_knots || !pt.is_finite() {
|
if self.choosing_objects || self.choosing_method || self.choosing_knots || !pt.is_finite() {
|
||||||
return CmdResult::NeedPoint;
|
return CmdResult::NeedPoint;
|
||||||
}
|
}
|
||||||
if self.choosing_tangent {
|
if self.choosing_tangent {
|
||||||
@@ -207,6 +262,14 @@ impl CadCommand for SplineCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_enter(&mut self) -> CmdResult {
|
fn on_enter(&mut self) -> CmdResult {
|
||||||
|
if self.choosing_objects {
|
||||||
|
let replacements = self.selected_objects.iter().filter_map(|handle| {
|
||||||
|
self.convertible.get(handle).map(|spline| (*handle, vec![EntityType::Spline(spline.clone())]))
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
return if replacements.is_empty() { CmdResult::Cancel }
|
||||||
|
else { CmdResult::ReplaceMany(replacements, Vec::new()) };
|
||||||
|
}
|
||||||
|
|
||||||
if self.choosing_method || self.choosing_knots {
|
if self.choosing_method || self.choosing_knots {
|
||||||
self.choosing_method = false;
|
self.choosing_method = false;
|
||||||
self.choosing_knots = false;
|
self.choosing_knots = false;
|
||||||
@@ -220,7 +283,13 @@ impl CadCommand for SplineCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn enter_accepts_default_start(&self) -> bool {
|
fn enter_accepts_default_start(&self) -> bool {
|
||||||
self.pts.is_empty() && !self.choosing_method
|
self.pts.is_empty() && !self.choosing_method && !self.choosing_objects
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_selection_gathering(&self) -> bool { self.choosing_objects }
|
||||||
|
fn on_selection_complete(&mut self, handles: Vec<Handle>) -> CmdResult {
|
||||||
|
self.selected_objects = handles.into_iter().filter(|handle| self.convertible.contains_key(handle)).collect();
|
||||||
|
self.on_enter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_escape(&mut self) -> CmdResult {
|
fn on_escape(&mut self) -> CmdResult {
|
||||||
@@ -265,6 +334,10 @@ impl CadCommand for SplineCommand {
|
|||||||
self.choosing_tangent = true;
|
self.choosing_tangent = true;
|
||||||
Some(CmdResult::NeedPoint)
|
Some(CmdResult::NeedPoint)
|
||||||
}
|
}
|
||||||
|
"O" | "OBJECT" if self.pts.is_empty() => {
|
||||||
|
self.choosing_objects = true;
|
||||||
|
Some(CmdResult::NeedPoint)
|
||||||
|
}
|
||||||
"M" | "METHOD" if self.pts.is_empty() => {
|
"M" | "METHOD" if self.pts.is_empty() => {
|
||||||
self.choosing_method = true;
|
self.choosing_method = true;
|
||||||
Some(CmdResult::NeedPoint)
|
Some(CmdResult::NeedPoint)
|
||||||
|
|||||||
Reference in new issue
Block a user