forked from 1b-agent/opencadstudio-upstream
Merge pull request #894 from ramox81/codex/fix-dimcontinue-parity
Complete continued dimension workflow
This commit is contained in:
4 files changed
+748
-176
No files matched your search
@@ -647,18 +647,15 @@ impl OpenCADStudio {
|
|||||||
"DIMCONTINUE" => {
|
"DIMCONTINUE" => {
|
||||||
use crate::modules::annotate::dim_continue::DimContinueCommand;
|
use crate::modules::annotate::dim_continue::DimContinueCommand;
|
||||||
let scene = &self.tabs[i].scene;
|
let scene = &self.tabs[i].scene;
|
||||||
let preserve_base_style = self.dimension_continue_mode == 1;
|
let recent = scene
|
||||||
let cmd = scene
|
|
||||||
.last_created_dimension
|
.last_created_dimension
|
||||||
.filter(|handle| scene.entity_belongs_to_active_space(*handle))
|
.filter(|handle| scene.entity_belongs_to_active_space(*handle))
|
||||||
.and_then(|handle| scene.document.get_entity(handle))
|
.and_then(|handle| scene.document.get_entity(handle))
|
||||||
.and_then(|entity| match entity {
|
.cloned();
|
||||||
acadrust::EntityType::Dimension(dimension) => Some(
|
let cmd = DimContinueCommand::new(
|
||||||
DimContinueCommand::from_dimension(dimension, preserve_base_style),
|
recent,
|
||||||
),
|
self.dimension_continue_mode == 1,
|
||||||
_ => None,
|
);
|
||||||
})
|
|
||||||
.unwrap_or_else(|| DimContinueCommand::new(preserve_base_style));
|
|
||||||
self.command_line.push_info(&cmd.prompt());
|
self.command_line.push_info(&cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -2479,16 +2479,23 @@ impl OpenCADStudio {
|
|||||||
self.commit_entity_handle_with_dimension_policy(entity, false)
|
self.commit_entity_handle_with_dimension_policy(entity, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit an entity while optionally retaining a dimension's source layer
|
/// Commit an entity, optionally preserving its source dimension style.
|
||||||
/// and dimension style. DIMCONTINUEMODE=1 uses this path; ordinary
|
|
||||||
/// creation continues to receive the current ribbon/style defaults.
|
|
||||||
pub(super) fn commit_entity_handle_with_dimension_policy(
|
pub(super) fn commit_entity_handle_with_dimension_policy(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut entity: acadrust::EntityType,
|
mut entity: acadrust::EntityType,
|
||||||
preserve_dimension_layer_and_style: bool,
|
preserve_dimension_layer_and_style: bool,
|
||||||
) -> Option<Handle> {
|
) -> Option<Handle> {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
let is_dimension = matches!(&entity, acadrust::EntityType::Dimension(_));
|
let tracks_dimension_chain = matches!(
|
||||||
|
&entity,
|
||||||
|
acadrust::EntityType::Dimension(
|
||||||
|
acadrust::entities::Dimension::Linear(_)
|
||||||
|
| acadrust::entities::Dimension::Aligned(_)
|
||||||
|
| acadrust::entities::Dimension::Angular2Ln(_)
|
||||||
|
| acadrust::entities::Dimension::Angular3Pt(_)
|
||||||
|
| acadrust::entities::Dimension::Ordinate(_)
|
||||||
|
)
|
||||||
|
);
|
||||||
let inherited_dimension = if preserve_dimension_layer_and_style {
|
let inherited_dimension = if preserve_dimension_layer_and_style {
|
||||||
match &entity {
|
match &entity {
|
||||||
acadrust::EntityType::Dimension(dimension) => Some((
|
acadrust::EntityType::Dimension(dimension) => Some((
|
||||||
@@ -2766,7 +2773,7 @@ impl OpenCADStudio {
|
|||||||
self.tabs[i].last_draw_anchor = Some(handle);
|
self.tabs[i].last_draw_anchor = Some(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_dimension {
|
if tracks_dimension_chain {
|
||||||
self.tabs[i].scene.last_created_dimension = new_handle;
|
self.tabs[i].scene.last_created_dimension = new_handle;
|
||||||
}
|
}
|
||||||
new_handle
|
new_handle
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
use acadrust::entities::{Dimension, DimensionBase, DimensionLinear};
|
use acadrust::entities::{
|
||||||
|
Dimension, DimensionAngular2Ln, DimensionAngular3Pt, DimensionBase, DimensionLinear,
|
||||||
|
DimensionOrdinate,
|
||||||
|
};
|
||||||
use acadrust::types::Vector3;
|
use acadrust::types::Vector3;
|
||||||
use acadrust::EntityType;
|
use acadrust::{EntityType, Handle};
|
||||||
|
use cadkernel::geom2d::{
|
||||||
|
arc_span, closest_point, intersect, nearest_of, Arc, Curve, Ray, Tolerance, Transform, Vec2,
|
||||||
|
XLine,
|
||||||
|
};
|
||||||
use cadkernel::space::Plane;
|
use cadkernel::space::Plane;
|
||||||
use glam::DVec3;
|
use glam::DVec3;
|
||||||
|
|
||||||
use crate::command::{CadCommand, CmdResult, DimensionAssociationInput};
|
use crate::command::{CadCommand, CmdOption, CmdResult, DimensionAssociationInput};
|
||||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||||
use crate::scene::model::wire_model::WireModel;
|
use crate::scene::model::wire_model::WireModel;
|
||||||
use crate::t;
|
|
||||||
|
|
||||||
pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/dim_continue.svg"));
|
pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/dim_continue.svg"));
|
||||||
|
|
||||||
@@ -49,82 +55,263 @@ impl SourceStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum ContinueKind {
|
||||||
|
Linear {
|
||||||
|
current: Vec2,
|
||||||
|
rotation: f64,
|
||||||
|
perpendicular: Vec2,
|
||||||
|
line_coordinate: f64,
|
||||||
|
},
|
||||||
|
Angular2Ln {
|
||||||
|
vertex: Vec2,
|
||||||
|
current: Vec2,
|
||||||
|
radius: f64,
|
||||||
|
},
|
||||||
|
Angular3Pt {
|
||||||
|
vertex: Vec2,
|
||||||
|
current: Vec2,
|
||||||
|
radius: f64,
|
||||||
|
},
|
||||||
|
Ordinate {
|
||||||
|
definition: Vec2,
|
||||||
|
leader: Vec2,
|
||||||
|
is_x: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct ContinueState {
|
struct ContinueState {
|
||||||
chain_p1: [f64; 2],
|
kind: ContinueKind,
|
||||||
rotation: f64,
|
|
||||||
dim_line_perp: f64,
|
|
||||||
perpendicular: [f64; 2],
|
|
||||||
plane: Plane,
|
|
||||||
style: SourceStyle,
|
style: SourceStyle,
|
||||||
|
plane: Plane,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DimContinueCommand {
|
pub struct DimContinueCommand {
|
||||||
state: Option<ContinueState>,
|
base: Option<ContinueState>,
|
||||||
|
injected: Option<EntityType>,
|
||||||
|
history: Vec<ContinueState>,
|
||||||
preserve_base_style: bool,
|
preserve_base_style: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DimContinueCommand {
|
impl DimContinueCommand {
|
||||||
pub fn new(preserve_base_style: bool) -> Self {
|
pub fn new(recent: Option<EntityType>, preserve_base_style: bool) -> Self {
|
||||||
Self {
|
let mut command = Self {
|
||||||
state: None,
|
base: None,
|
||||||
|
injected: None,
|
||||||
|
history: Vec::new(),
|
||||||
preserve_base_style,
|
preserve_base_style,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_dimension(dimension: &Dimension, preserve_base_style: bool) -> Self {
|
|
||||||
let (first, second, definition, rotation) = match dimension {
|
|
||||||
Dimension::Linear(source) => (
|
|
||||||
source.first_point,
|
|
||||||
source.second_point,
|
|
||||||
source.base.definition_point,
|
|
||||||
source.rotation,
|
|
||||||
),
|
|
||||||
Dimension::Aligned(source) => {
|
|
||||||
let plane = plane_from_normal(source.first_point, source.base.normal);
|
|
||||||
let first = plane.project(point(source.first_point)).unwrap_or([0.0; 2]);
|
|
||||||
let second = plane.project(point(source.second_point)).unwrap_or(first);
|
|
||||||
let delta = [second[0] - first[0], second[1] - first[1]];
|
|
||||||
(
|
|
||||||
source.first_point,
|
|
||||||
source.second_point,
|
|
||||||
source.base.definition_point,
|
|
||||||
delta[1].atan2(delta[0]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => return Self::new(preserve_base_style),
|
|
||||||
};
|
};
|
||||||
let plane = plane_from_normal(first, dimension.base().normal);
|
if let Some(entity) = recent {
|
||||||
let second = plane.project(point(second)).unwrap_or([0.0; 2]);
|
let _ = command.install_base(&entity, None);
|
||||||
let definition = plane.project(point(definition)).unwrap_or(second);
|
}
|
||||||
let perpendicular = [-rotation.sin(), rotation.cos()];
|
command
|
||||||
let dim_line_perp = dot(definition, perpendicular);
|
}
|
||||||
Self {
|
|
||||||
state: Some(ContinueState {
|
fn install_base(&mut self, entity: &EntityType, pick_world: Option<DVec3>) -> bool {
|
||||||
chain_p1: second,
|
let EntityType::Dimension(dimension) = entity else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let style = SourceStyle::from_base(dimension.base());
|
||||||
|
let plane = plane_from_normal(dimension.base().definition_point, style.normal);
|
||||||
|
let pick = pick_world.and_then(|point| plane.project(point.to_array()).map(Vec2::from));
|
||||||
|
let kind = match dimension {
|
||||||
|
Dimension::Linear(source) => {
|
||||||
|
let rotation = source.rotation;
|
||||||
|
let perpendicular = Vec2::new(-rotation.sin(), rotation.cos());
|
||||||
|
ContinueKind::Linear {
|
||||||
|
current: selected_linear_end(
|
||||||
|
project(&plane, source.first_point),
|
||||||
|
project(&plane, source.second_point),
|
||||||
|
pick,
|
||||||
|
),
|
||||||
|
rotation,
|
||||||
|
perpendicular,
|
||||||
|
line_coordinate: project(&plane, source.base.definition_point)
|
||||||
|
.dot(perpendicular),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dimension::Aligned(source) => {
|
||||||
|
let first = project(&plane, source.first_point);
|
||||||
|
let second = project(&plane, source.second_point);
|
||||||
|
let Some(direction) = (second - first).normalize() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let rotation = direction.angle();
|
||||||
|
let perpendicular = direction.perpendicular();
|
||||||
|
ContinueKind::Linear {
|
||||||
|
current: selected_linear_end(first, second, pick),
|
||||||
|
rotation,
|
||||||
|
perpendicular,
|
||||||
|
line_coordinate: project(&plane, source.base.definition_point)
|
||||||
|
.dot(perpendicular),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dimension::Angular2Ln(source) => {
|
||||||
|
let lines = [
|
||||||
|
[
|
||||||
|
project(&plane, source.first_point),
|
||||||
|
project(&plane, source.second_point),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
project(&plane, source.angle_vertex),
|
||||||
|
project(&plane, source.definition_point),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
let vertex = angular2_vertex(lines).unwrap_or(lines[1][0]);
|
||||||
|
ContinueKind::Angular2Ln {
|
||||||
|
vertex,
|
||||||
|
current: selected_angular_end(vertex, [lines[0][1], lines[1][1]], pick),
|
||||||
|
radius: project(&plane, source.dimension_arc)
|
||||||
|
.distance(vertex)
|
||||||
|
.max(1.0e-9),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dimension::Angular3Pt(source) => {
|
||||||
|
let vertex = project(&plane, source.angle_vertex);
|
||||||
|
ContinueKind::Angular3Pt {
|
||||||
|
vertex,
|
||||||
|
current: selected_angular_end(
|
||||||
|
vertex,
|
||||||
|
[
|
||||||
|
project(&plane, source.first_point),
|
||||||
|
project(&plane, source.second_point),
|
||||||
|
],
|
||||||
|
pick,
|
||||||
|
),
|
||||||
|
radius: project(&plane, source.definition_point)
|
||||||
|
.distance(vertex)
|
||||||
|
.max(1.0e-9),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dimension::Ordinate(source) => ContinueKind::Ordinate {
|
||||||
|
definition: project(&plane, source.definition_point),
|
||||||
|
leader: project(&plane, source.leader_endpoint),
|
||||||
|
is_x: source.is_ordinate_type_x,
|
||||||
|
},
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
self.base = Some(ContinueState { kind, style, plane });
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_dimension(&self, point_world: DVec3) -> Option<Dimension> {
|
||||||
|
let state = self.base.as_ref()?;
|
||||||
|
let point = state.plane.project(point_world.to_array()).map(Vec2::from)?;
|
||||||
|
let mut dimension = match &state.kind {
|
||||||
|
ContinueKind::Linear {
|
||||||
|
current,
|
||||||
rotation,
|
rotation,
|
||||||
dim_line_perp,
|
|
||||||
perpendicular,
|
perpendicular,
|
||||||
plane,
|
line_coordinate,
|
||||||
style: SourceStyle::from_base(dimension.base()),
|
} => build_linear(
|
||||||
}),
|
state.plane,
|
||||||
preserve_base_style,
|
*current,
|
||||||
|
point,
|
||||||
|
*rotation,
|
||||||
|
*perpendicular,
|
||||||
|
*line_coordinate,
|
||||||
|
),
|
||||||
|
ContinueKind::Angular2Ln {
|
||||||
|
vertex,
|
||||||
|
current,
|
||||||
|
radius,
|
||||||
|
} => {
|
||||||
|
let previous = *current - *vertex;
|
||||||
|
let moving = point - *vertex;
|
||||||
|
let (definition, text) =
|
||||||
|
angular_definition_and_text(*vertex, previous, moving, *radius)?;
|
||||||
|
let mut result = DimensionAngular2Ln::default();
|
||||||
|
result.first_point = world(state.plane, *vertex);
|
||||||
|
result.second_point = world(state.plane, *current);
|
||||||
|
result.angle_vertex = world(state.plane, *vertex);
|
||||||
|
result.definition_point = world(state.plane, point);
|
||||||
|
result.dimension_arc = world(state.plane, definition);
|
||||||
|
result.base.definition_point = result.dimension_arc;
|
||||||
|
result.base.text_middle_point = world(state.plane, text);
|
||||||
|
result.base.insertion_point = result.base.text_middle_point;
|
||||||
|
Dimension::Angular2Ln(result)
|
||||||
|
}
|
||||||
|
ContinueKind::Angular3Pt {
|
||||||
|
vertex,
|
||||||
|
current,
|
||||||
|
radius,
|
||||||
|
} => {
|
||||||
|
let previous = *current - *vertex;
|
||||||
|
let moving = point - *vertex;
|
||||||
|
let (definition, text) =
|
||||||
|
angular_definition_and_text(*vertex, previous, moving, *radius)?;
|
||||||
|
let mut result = DimensionAngular3Pt::new(
|
||||||
|
world(state.plane, *vertex),
|
||||||
|
world(state.plane, *current),
|
||||||
|
world(state.plane, point),
|
||||||
|
);
|
||||||
|
result.definition_point = world(state.plane, definition);
|
||||||
|
result.base.definition_point = result.definition_point;
|
||||||
|
result.base.text_middle_point = world(state.plane, text);
|
||||||
|
result.base.insertion_point = result.base.text_middle_point;
|
||||||
|
Dimension::Angular3Pt(result)
|
||||||
|
}
|
||||||
|
ContinueKind::Ordinate {
|
||||||
|
definition,
|
||||||
|
leader,
|
||||||
|
is_x,
|
||||||
|
} => {
|
||||||
|
let to_dimension = Transform::rotation(-state.style.horizontal_direction);
|
||||||
|
let from_dimension = Transform::rotation(state.style.horizontal_direction);
|
||||||
|
let feature = Vec2::from(to_dimension.apply_point(point.into()));
|
||||||
|
let source_leader = Vec2::from(to_dimension.apply_point((*leader).into()));
|
||||||
|
let leader = if *is_x {
|
||||||
|
Vec2::new(feature.x, source_leader.y)
|
||||||
|
} else {
|
||||||
|
Vec2::new(source_leader.x, feature.y)
|
||||||
|
};
|
||||||
|
let leader = Vec2::from(from_dimension.apply_point(leader.into()));
|
||||||
|
let mut result = DimensionOrdinate::new(
|
||||||
|
world(state.plane, point),
|
||||||
|
world(state.plane, leader),
|
||||||
|
*is_x,
|
||||||
|
);
|
||||||
|
result.definition_point = world(state.plane, *definition);
|
||||||
|
result.base.definition_point = result.definition_point;
|
||||||
|
result.base.text_middle_point = result.leader_endpoint;
|
||||||
|
result.base.insertion_point = result.base.text_middle_point;
|
||||||
|
Dimension::Ordinate(result)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
state.style.apply(dimension.base_mut());
|
||||||
|
refresh_measurement(&mut dimension, state.plane);
|
||||||
|
dimension.base_mut().common.handle = Handle::NULL;
|
||||||
|
dimension.base_mut().block_name.clear();
|
||||||
|
Some(dimension)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self, point_world: DVec3) {
|
||||||
|
let Some(point) = self
|
||||||
|
.base
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|state| state.plane.project(point_world.to_array()))
|
||||||
|
.map(Vec2::from)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(state) = self.base.as_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
match &mut state.kind {
|
||||||
|
ContinueKind::Linear { current, .. }
|
||||||
|
| ContinueKind::Angular2Ln { current, .. }
|
||||||
|
| ContinueKind::Angular3Pt { current, .. } => *current = point,
|
||||||
|
ContinueKind::Ordinate { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn placement(&self, point_world: DVec3) -> Option<([f64; 2], [f64; 2], [f64; 2])> {
|
fn undo_one(&mut self) -> CmdResult {
|
||||||
let state = self.state.as_ref()?;
|
let Some(previous) = self.history.pop() else {
|
||||||
let second = state.plane.project(point_world.to_array())?;
|
return CmdResult::NeedPoint;
|
||||||
let first_line = project_to_line(
|
};
|
||||||
state.chain_p1,
|
self.base = Some(previous);
|
||||||
state.perpendicular,
|
CmdResult::UndoDocument
|
||||||
state.dim_line_perp,
|
|
||||||
);
|
|
||||||
let second_line = project_to_line(
|
|
||||||
second,
|
|
||||||
state.perpendicular,
|
|
||||||
state.dim_line_perp,
|
|
||||||
);
|
|
||||||
Some((second, first_line, second_line))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,44 +321,64 @@ impl CadCommand for DimContinueCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prompt(&self) -> String {
|
fn prompt(&self) -> String {
|
||||||
if self.state.is_none() {
|
if self.base.is_none() {
|
||||||
t!("DIMCONTINUE No base dimension found. Place a dimension first.").into_owned()
|
"DIMCONTINUE Select continued dimension:".to_string()
|
||||||
|
} else if self
|
||||||
|
.base
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|base| matches!(&base.kind, ContinueKind::Ordinate { .. }))
|
||||||
|
{
|
||||||
|
"DIMCONTINUE Specify feature location [Undo/Select] <Select>:".to_string()
|
||||||
} else {
|
} else {
|
||||||
t!("DIMCONTINUE Specify a second extension line origin (Enter to exit):").into_owned()
|
"DIMCONTINUE Specify second extension line origin [Select/Undo] <Select>:"
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_point(&mut self, point_world: DVec3) -> CmdResult {
|
fn options(&self) -> Vec<CmdOption> {
|
||||||
let Some((second, first_line, second_line)) = self.placement(point_world) else {
|
self.base.as_ref().map_or_else(Vec::new, |base| {
|
||||||
return CmdResult::Cancel;
|
if matches!(&base.kind, ContinueKind::Ordinate { .. }) {
|
||||||
};
|
vec![CmdOption::new("Undo", "U"), CmdOption::new("Select", "S")]
|
||||||
let state = self.state.as_mut().expect("continue state");
|
} else {
|
||||||
let mut dimension = DimensionLinear::new(
|
vec![CmdOption::new("Select", "S"), CmdOption::new("Undo", "U")]
|
||||||
vector3(state.plane.point_at(state.chain_p1)),
|
}
|
||||||
vector3(state.plane.point_at(second)),
|
})
|
||||||
);
|
}
|
||||||
dimension.rotation = state.rotation;
|
|
||||||
state.style.apply(&mut dimension.base);
|
|
||||||
dimension.definition_point = vector3(state.plane.point_at(first_line));
|
|
||||||
dimension.base.definition_point = dimension.definition_point;
|
|
||||||
dimension.base.text_middle_point = vector3(state.plane.point_at([
|
|
||||||
(first_line[0] + second_line[0]) * 0.5,
|
|
||||||
(first_line[1] + second_line[1]) * 0.5,
|
|
||||||
]));
|
|
||||||
dimension.base.insertion_point = dimension.base.text_middle_point;
|
|
||||||
let axis = [state.rotation.cos(), state.rotation.sin()];
|
|
||||||
dimension.base.actual_measurement = dot(
|
|
||||||
[
|
|
||||||
second[0] - state.chain_p1[0],
|
|
||||||
second[1] - state.chain_p1[1],
|
|
||||||
],
|
|
||||||
axis,
|
|
||||||
)
|
|
||||||
.abs();
|
|
||||||
state.chain_p1 = second;
|
|
||||||
|
|
||||||
|
fn needs_entity_pick(&self) -> bool {
|
||||||
|
self.base.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn entity_pick_highlights_hover(&self) -> bool {
|
||||||
|
self.base.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inject_before_entity_pick(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inject_picked_entity(&mut self, entity: EntityType) {
|
||||||
|
self.injected = Some(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_entity_pick(&mut self, _handle: Handle, point: DVec3) -> CmdResult {
|
||||||
|
let Some(entity) = self.injected.take() else {
|
||||||
|
return CmdResult::NeedPoint;
|
||||||
|
};
|
||||||
|
let _ = self.install_base(&entity, Some(point));
|
||||||
|
CmdResult::NeedPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_point(&mut self, point: DVec3) -> CmdResult {
|
||||||
|
let Some(dimension) = self.build_dimension(point) else {
|
||||||
|
return CmdResult::NeedPoint;
|
||||||
|
};
|
||||||
|
if let Some(base) = self.base.clone() {
|
||||||
|
self.history.push(base);
|
||||||
|
}
|
||||||
|
self.advance(point);
|
||||||
CmdResult::CommitDimension {
|
CmdResult::CommitDimension {
|
||||||
entity: EntityType::Dimension(Dimension::Linear(dimension)),
|
entity: EntityType::Dimension(dimension),
|
||||||
association: DimensionAssociationInput::Infer(None),
|
association: DimensionAssociationInput::Infer(None),
|
||||||
preserve_base_style: self.preserve_base_style,
|
preserve_base_style: self.preserve_base_style,
|
||||||
continue_command: true,
|
continue_command: true,
|
||||||
@@ -179,59 +386,423 @@ impl CadCommand for DimContinueCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_enter(&mut self) -> CmdResult {
|
fn on_enter(&mut self) -> CmdResult {
|
||||||
CmdResult::Cancel
|
if self.base.take().is_some() {
|
||||||
|
CmdResult::NeedPoint
|
||||||
|
} else {
|
||||||
|
CmdResult::Cancel
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_mouse_move(&mut self, point_world: DVec3) -> Option<WireModel> {
|
fn wants_text_input(&self) -> bool {
|
||||||
let (second, first_line, second_line) = self.placement(point_world)?;
|
self.base.is_some()
|
||||||
let state = self.state.as_ref()?;
|
|
||||||
let first = state.plane.point_at(state.chain_p1);
|
|
||||||
let second = state.plane.point_at(second);
|
|
||||||
let first_line = state.plane.point_at(first_line);
|
|
||||||
let second_line = state.plane.point_at(second_line);
|
|
||||||
Some(WireModel {
|
|
||||||
point_marker: None,
|
|
||||||
taper_widths: Vec::new(),
|
|
||||||
pattern_stations: Vec::new(),
|
|
||||||
world_width: 0.0,
|
|
||||||
depth_override: None,
|
|
||||||
display_visible: true,
|
|
||||||
plot_visible: true,
|
|
||||||
fill_is_3d: false,
|
|
||||||
fill_is_2d_solid: false,
|
|
||||||
render_instance: None,
|
|
||||||
pick_tris: Vec::new(),
|
|
||||||
pick_tris_low: Vec::new(),
|
|
||||||
dash_from_start: false,
|
|
||||||
dash_align_end: None,
|
|
||||||
text_verts: Vec::new(),
|
|
||||||
name: "dimcont_preview".into(),
|
|
||||||
points: vec![
|
|
||||||
float3(first),
|
|
||||||
float3(first_line),
|
|
||||||
[f32::NAN, 0.0, 0.0],
|
|
||||||
float3(second),
|
|
||||||
float3(second_line),
|
|
||||||
[f32::NAN, 0.0, 0.0],
|
|
||||||
float3(first_line),
|
|
||||||
float3(second_line),
|
|
||||||
],
|
|
||||||
points_low: Vec::new(),
|
|
||||||
color: WireModel::CYAN,
|
|
||||||
selected: false,
|
|
||||||
pattern_length: 0.0,
|
|
||||||
pattern: [0.0; 8],
|
|
||||||
line_weight_px: 1.0,
|
|
||||||
snap_pts: Vec::new(),
|
|
||||||
tangent_geoms: Vec::new(),
|
|
||||||
aci: 0,
|
|
||||||
key_vertices: Vec::new(),
|
|
||||||
aabb: WireModel::UNBOUNDED_AABB,
|
|
||||||
plinegen: true,
|
|
||||||
fill_tris: Vec::new(),
|
|
||||||
fill_tris_low: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn point_step_accepts_keywords(&self) -> bool {
|
||||||
|
self.base.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||||
|
match text.trim().to_ascii_uppercase().as_str() {
|
||||||
|
"S" | "SELECT" => {
|
||||||
|
self.base = None;
|
||||||
|
Some(CmdResult::NeedPoint)
|
||||||
|
}
|
||||||
|
"U" | "UNDO" => Some(self.undo_one()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_undo_step(&mut self) -> Option<CmdResult> {
|
||||||
|
if self.history.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.undo_one())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_mouse_move(&mut self, point: DVec3) -> Option<WireModel> {
|
||||||
|
self.build_dimension(point)
|
||||||
|
.map(|dimension| preview_for_dimension(&dimension))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_linear(
|
||||||
|
plane: Plane,
|
||||||
|
first: Vec2,
|
||||||
|
second: Vec2,
|
||||||
|
rotation: f64,
|
||||||
|
perpendicular: Vec2,
|
||||||
|
line_coordinate: f64,
|
||||||
|
) -> Dimension {
|
||||||
|
let first_line = project_to_line(first, perpendicular, line_coordinate);
|
||||||
|
let second_line = project_to_line(second, perpendicular, line_coordinate);
|
||||||
|
let mut result = DimensionLinear::new(world(plane, first), world(plane, second));
|
||||||
|
result.rotation = rotation;
|
||||||
|
result.definition_point = world(plane, second_line);
|
||||||
|
result.base.definition_point = result.definition_point;
|
||||||
|
result.base.text_middle_point = world(plane, first_line.lerp(second_line, 0.5));
|
||||||
|
result.base.insertion_point = result.base.text_middle_point;
|
||||||
|
Dimension::Linear(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selected_linear_end(first: Vec2, second: Vec2, pick: Option<Vec2>) -> Vec2 {
|
||||||
|
pick.map_or(second, |point| {
|
||||||
|
if point.distance_squared(first) <= point.distance_squared(second) {
|
||||||
|
first
|
||||||
|
} else {
|
||||||
|
second
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selected_angular_end(vertex: Vec2, ends: [Vec2; 2], pick: Option<Vec2>) -> Vec2 {
|
||||||
|
let Some(pick) = pick else {
|
||||||
|
return ends[0];
|
||||||
|
};
|
||||||
|
let rays = ends.map(|end| {
|
||||||
|
Curve::Ray(Ray {
|
||||||
|
origin: vertex.into(),
|
||||||
|
direction: (end - vertex).into(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
nearest_of(rays.iter(), pick.into())
|
||||||
|
.map(|(index, _)| ends[index])
|
||||||
|
.unwrap_or(ends[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn angular2_vertex(lines: [[Vec2; 2]; 2]) -> Option<Vec2> {
|
||||||
|
let first = Curve::XLine(XLine {
|
||||||
|
base: lines[0][0].into(),
|
||||||
|
direction: (lines[0][1] - lines[0][0]).into(),
|
||||||
|
});
|
||||||
|
let second = Curve::XLine(XLine {
|
||||||
|
base: lines[1][0].into(),
|
||||||
|
direction: (lines[1][1] - lines[1][0]).into(),
|
||||||
|
});
|
||||||
|
let scale = (lines[0][1] - lines[0][0])
|
||||||
|
.length()
|
||||||
|
.max((lines[1][1] - lines[1][0]).length())
|
||||||
|
.max(1.0);
|
||||||
|
intersect(&first, &second, Tolerance::new(scale * 1.0e-9))
|
||||||
|
.first()
|
||||||
|
.map(|crossing| Vec2::from(crossing.point))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn angular_definition_and_text(
|
||||||
|
vertex: Vec2,
|
||||||
|
previous: Vec2,
|
||||||
|
moving: Vec2,
|
||||||
|
radius: f64,
|
||||||
|
) -> Option<(Vec2, Vec2)> {
|
||||||
|
let arc = angular_arc(vertex, previous, moving, radius)?;
|
||||||
|
Some((
|
||||||
|
Vec2::from(arc.point_at(2.0 / 3.0)),
|
||||||
|
Vec2::from(arc.point_at(0.5)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn angular_arc(vertex: Vec2, first: Vec2, second: Vec2, radius: f64) -> Option<Curve> {
|
||||||
|
let first = first.normalize()?;
|
||||||
|
let second = second.normalize()?;
|
||||||
|
if first.distance_squared(second) <= 1.0e-18 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let first_angle = first.angle();
|
||||||
|
let second_angle = second.angle();
|
||||||
|
let (start_angle, end_angle) =
|
||||||
|
if arc_span(first_angle, second_angle) <= std::f64::consts::PI {
|
||||||
|
(first_angle, second_angle)
|
||||||
|
} else {
|
||||||
|
(second_angle, first_angle)
|
||||||
|
};
|
||||||
|
Some(Curve::Arc(Arc {
|
||||||
|
centre: vertex.into(),
|
||||||
|
radius,
|
||||||
|
start_angle,
|
||||||
|
end_angle,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refresh_measurement(dimension: &mut Dimension, plane: Plane) {
|
||||||
|
match dimension {
|
||||||
|
Dimension::Linear(value) => {
|
||||||
|
let first = project(&plane, value.first_point);
|
||||||
|
let second = project(&plane, value.second_point);
|
||||||
|
let axis = Vec2::new(value.rotation.cos(), value.rotation.sin());
|
||||||
|
value.base.actual_measurement = (second - first).dot(axis).abs();
|
||||||
|
}
|
||||||
|
Dimension::Angular2Ln(value) => {
|
||||||
|
value.base.actual_measurement = value.measurement_degrees()
|
||||||
|
}
|
||||||
|
Dimension::Angular3Pt(value) => {
|
||||||
|
value.base.actual_measurement = value.measurement_degrees()
|
||||||
|
}
|
||||||
|
Dimension::Ordinate(value) => value.refresh_measurement(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preview_for_dimension(dimension: &Dimension) -> WireModel {
|
||||||
|
let mut points = Vec::<[f64; 3]>::new();
|
||||||
|
match dimension {
|
||||||
|
Dimension::Linear(value) => {
|
||||||
|
let plane = plane_from_normal(value.first_point, value.base.normal);
|
||||||
|
linear_preview(
|
||||||
|
&mut points,
|
||||||
|
plane,
|
||||||
|
project(&plane, value.first_point),
|
||||||
|
project(&plane, value.second_point),
|
||||||
|
value.rotation,
|
||||||
|
project(&plane, value.definition_point),
|
||||||
|
project(&plane, value.base.text_middle_point),
|
||||||
|
value.base.actual_measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Dimension::Angular2Ln(value) => {
|
||||||
|
let plane = plane_from_normal(value.first_point, value.base.normal);
|
||||||
|
let lines = [
|
||||||
|
[
|
||||||
|
project(&plane, value.first_point),
|
||||||
|
project(&plane, value.second_point),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
project(&plane, value.angle_vertex),
|
||||||
|
project(&plane, value.definition_point),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
let vertex = angular2_vertex(lines).unwrap_or(lines[1][0]);
|
||||||
|
angular_preview(
|
||||||
|
&mut points,
|
||||||
|
plane,
|
||||||
|
vertex,
|
||||||
|
lines[0][1] - vertex,
|
||||||
|
lines[1][1] - vertex,
|
||||||
|
project(&plane, value.dimension_arc),
|
||||||
|
project(&plane, value.base.text_middle_point),
|
||||||
|
value.base.actual_measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Dimension::Angular3Pt(value) => {
|
||||||
|
let plane = plane_from_normal(value.angle_vertex, value.base.normal);
|
||||||
|
let vertex = project(&plane, value.angle_vertex);
|
||||||
|
angular_preview(
|
||||||
|
&mut points,
|
||||||
|
plane,
|
||||||
|
vertex,
|
||||||
|
project(&plane, value.first_point) - vertex,
|
||||||
|
project(&plane, value.second_point) - vertex,
|
||||||
|
project(&plane, value.definition_point),
|
||||||
|
project(&plane, value.base.text_middle_point),
|
||||||
|
value.base.actual_measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Dimension::Ordinate(value) => {
|
||||||
|
let plane = plane_from_normal(value.definition_point, value.base.normal);
|
||||||
|
ordinate_preview(
|
||||||
|
&mut points,
|
||||||
|
plane,
|
||||||
|
project(&plane, value.feature_location),
|
||||||
|
project(&plane, value.leader_endpoint),
|
||||||
|
value.base.actual_measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
WireModel::solid_f64(
|
||||||
|
"dimcontinue_preview".to_string(),
|
||||||
|
points,
|
||||||
|
WireModel::CYAN,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linear_preview(
|
||||||
|
points: &mut Vec<[f64; 3]>,
|
||||||
|
plane: Plane,
|
||||||
|
first: Vec2,
|
||||||
|
second: Vec2,
|
||||||
|
rotation: f64,
|
||||||
|
definition: Vec2,
|
||||||
|
text: Vec2,
|
||||||
|
measurement: f64,
|
||||||
|
) {
|
||||||
|
let axis = Vec2::new(rotation.cos(), rotation.sin());
|
||||||
|
let perpendicular = axis.perpendicular();
|
||||||
|
let coordinate = definition.dot(perpendicular);
|
||||||
|
let first_line = project_to_line(first, perpendicular, coordinate);
|
||||||
|
let second_line = project_to_line(second, perpendicular, coordinate);
|
||||||
|
segment(points, plane, first, first_line);
|
||||||
|
segment(points, plane, second, second_line);
|
||||||
|
segment(points, plane, first_line, second_line);
|
||||||
|
arrow(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
first_line,
|
||||||
|
axis,
|
||||||
|
perpendicular,
|
||||||
|
first_line.distance(second_line),
|
||||||
|
);
|
||||||
|
arrow(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
second_line,
|
||||||
|
-axis,
|
||||||
|
perpendicular,
|
||||||
|
first_line.distance(second_line),
|
||||||
|
);
|
||||||
|
text_box(points, plane, text, axis, perpendicular, measurement);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn angular_preview(
|
||||||
|
points: &mut Vec<[f64; 3]>,
|
||||||
|
plane: Plane,
|
||||||
|
vertex: Vec2,
|
||||||
|
first: Vec2,
|
||||||
|
second: Vec2,
|
||||||
|
arc_point: Vec2,
|
||||||
|
text: Vec2,
|
||||||
|
measurement: f64,
|
||||||
|
) {
|
||||||
|
let radius = arc_point.distance(vertex).max(1.0e-9);
|
||||||
|
let Some(first_direction) = first.normalize() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(second_direction) = second.normalize() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(arc) = angular_arc(vertex, first, second, radius) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
segment(points, plane, vertex, vertex + first_direction * radius);
|
||||||
|
segment(points, plane, vertex, vertex + second_direction * radius);
|
||||||
|
for index in 0..=24 {
|
||||||
|
push_local(points, plane, Vec2::from(arc.point_at(index as f64 / 24.0)));
|
||||||
|
}
|
||||||
|
points.push([f64::NAN; 3]);
|
||||||
|
let start = Vec2::from(arc.point_at(0.0));
|
||||||
|
let start_next = Vec2::from(arc.point_at(1.0 / 1024.0));
|
||||||
|
let end = Vec2::from(arc.point_at(1.0));
|
||||||
|
let end_previous = Vec2::from(arc.point_at(1.0 - 1.0 / 1024.0));
|
||||||
|
arrow(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
start,
|
||||||
|
(start_next - start).normalize().unwrap_or(first_direction),
|
||||||
|
first_direction,
|
||||||
|
radius,
|
||||||
|
);
|
||||||
|
arrow(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
end,
|
||||||
|
(end_previous - end).normalize().unwrap_or(-second_direction),
|
||||||
|
second_direction,
|
||||||
|
radius,
|
||||||
|
);
|
||||||
|
let before_middle = Vec2::from(arc.point_at(0.5 - 1.0 / 1024.0));
|
||||||
|
let after_middle = Vec2::from(arc.point_at(0.5 + 1.0 / 1024.0));
|
||||||
|
let text_axis = (after_middle - before_middle)
|
||||||
|
.normalize()
|
||||||
|
.unwrap_or(Vec2::new(1.0, 0.0));
|
||||||
|
text_box(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
text,
|
||||||
|
text_axis,
|
||||||
|
text_axis.perpendicular(),
|
||||||
|
measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ordinate_preview(
|
||||||
|
points: &mut Vec<[f64; 3]>,
|
||||||
|
plane: Plane,
|
||||||
|
feature: Vec2,
|
||||||
|
leader: Vec2,
|
||||||
|
measurement: f64,
|
||||||
|
) {
|
||||||
|
segment(points, plane, feature, leader);
|
||||||
|
let axis = (leader - feature)
|
||||||
|
.normalize()
|
||||||
|
.unwrap_or(Vec2::new(0.0, 1.0));
|
||||||
|
let perpendicular = axis.perpendicular();
|
||||||
|
arrow(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
feature,
|
||||||
|
axis,
|
||||||
|
perpendicular,
|
||||||
|
feature.distance(leader),
|
||||||
|
);
|
||||||
|
text_box(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
leader,
|
||||||
|
perpendicular,
|
||||||
|
axis,
|
||||||
|
measurement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arrow(
|
||||||
|
points: &mut Vec<[f64; 3]>,
|
||||||
|
plane: Plane,
|
||||||
|
tip: Vec2,
|
||||||
|
inward: Vec2,
|
||||||
|
perpendicular: Vec2,
|
||||||
|
span: f64,
|
||||||
|
) {
|
||||||
|
let inward = inward.normalize().unwrap_or(Vec2::new(1.0, 0.0));
|
||||||
|
let perpendicular = perpendicular
|
||||||
|
.normalize()
|
||||||
|
.unwrap_or(Vec2::new(0.0, 1.0));
|
||||||
|
let size = span.clamp(1.0, 100.0) * 0.035;
|
||||||
|
let back = tip + inward * size;
|
||||||
|
segment(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
tip,
|
||||||
|
back + perpendicular * size * 0.4,
|
||||||
|
);
|
||||||
|
segment(
|
||||||
|
points,
|
||||||
|
plane,
|
||||||
|
tip,
|
||||||
|
back - perpendicular * size * 0.4,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_box(
|
||||||
|
points: &mut Vec<[f64; 3]>,
|
||||||
|
plane: Plane,
|
||||||
|
center: Vec2,
|
||||||
|
axis: Vec2,
|
||||||
|
perpendicular: Vec2,
|
||||||
|
measurement: f64,
|
||||||
|
) {
|
||||||
|
let digits = if measurement.abs() < 1.0 {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
measurement.abs().log10().floor() + 1.0
|
||||||
|
};
|
||||||
|
let half_width = (digits + 2.0) * 0.12;
|
||||||
|
let half_height = 0.16;
|
||||||
|
let a = center - axis * half_width - perpendicular * half_height;
|
||||||
|
let b = center + axis * half_width - perpendicular * half_height;
|
||||||
|
let c = center + axis * half_width + perpendicular * half_height;
|
||||||
|
let d = center - axis * half_width + perpendicular * half_height;
|
||||||
|
for point in [a, b, c, d, a] {
|
||||||
|
push_local(points, plane, point);
|
||||||
|
}
|
||||||
|
points.push([f64::NAN; 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn project_to_line(point: Vec2, perpendicular: Vec2, coordinate: f64) -> Vec2 {
|
||||||
|
let line = Curve::XLine(XLine {
|
||||||
|
base: (perpendicular * coordinate).into(),
|
||||||
|
direction: perpendicular.perpendicular().into(),
|
||||||
|
});
|
||||||
|
Vec2::from(closest_point(&line, point.into()).point)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn plane_from_normal(origin: Vector3, normal: Vector3) -> Plane {
|
fn plane_from_normal(origin: Vector3, normal: Vector3) -> Plane {
|
||||||
@@ -244,28 +815,27 @@ fn plane_from_normal(origin: Vector3, normal: Vector3) -> Plane {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn project_to_line(point: [f64; 2], perpendicular: [f64; 2], offset: f64) -> [f64; 2] {
|
fn project(plane: &Plane, value: Vector3) -> Vec2 {
|
||||||
let distance = offset - dot(point, perpendicular);
|
Vec2::from(plane.project(point(value)).unwrap_or([0.0; 2]))
|
||||||
[
|
|
||||||
point[0] + perpendicular[0] * distance,
|
|
||||||
point[1] + perpendicular[1] * distance,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dot(first: [f64; 2], second: [f64; 2]) -> f64 {
|
fn world(plane: Plane, value: Vec2) -> Vector3 {
|
||||||
first[0] * second[0] + first[1] * second[1]
|
let value = plane.point_at(value.into());
|
||||||
|
Vector3::new(value[0], value[1], value[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn point(value: Vector3) -> [f64; 3] {
|
fn point(value: Vector3) -> [f64; 3] {
|
||||||
[value.x, value.y, value.z]
|
[value.x, value.y, value.z]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vector3(value: [f64; 3]) -> Vector3 {
|
fn segment(points: &mut Vec<[f64; 3]>, plane: Plane, first: Vec2, second: Vec2) {
|
||||||
Vector3::new(value[0], value[1], value[2])
|
push_local(points, plane, first);
|
||||||
|
push_local(points, plane, second);
|
||||||
|
points.push([f64::NAN; 3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn float3(value: [f64; 3]) -> [f32; 3] {
|
fn push_local(points: &mut Vec<[f64; 3]>, plane: Plane, point: Vec2) {
|
||||||
[value[0] as f32, value[1] as f32, value[2] as f32]
|
points.push(plane.point_at(point.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
inventory::submit!(crate::command::CommandRegistration { names: &["DIMCONTINUE"] });
|
inventory::submit!(crate::command::CommandRegistration { names: &["DIMCONTINUE"] });
|
||||||
+2
-4
@@ -1420,10 +1420,8 @@ pub struct Scene {
|
|||||||
pub selection: Rc<RefCell<SelectionState>>,
|
pub selection: Rc<RefCell<SelectionState>>,
|
||||||
/// The CAD document — single source of truth for all entities.
|
/// The CAD document — single source of truth for all entities.
|
||||||
pub document: CadDocument,
|
pub document: CadDocument,
|
||||||
/// Last dimension created during this application session. This is
|
/// Last chain-compatible dimension created this session.
|
||||||
/// intentionally not reconstructed from file handles: continuation and
|
/// Never reconstructed from loaded file handles.
|
||||||
/// baseline commands must not treat an old, merely high-handle dimension
|
|
||||||
/// loaded from disk as the user's most recently created dimension.
|
|
||||||
pub last_created_dimension: Option<Handle>,
|
pub last_created_dimension: Option<Handle>,
|
||||||
/// File-open-prepared index for non-graphical semantic object lookups.
|
/// File-open-prepared index for non-graphical semantic object lookups.
|
||||||
pub(crate) object_data_cache: crate::entities::object_data::ObjectDataCache,
|
pub(crate) object_data_cache: crate::entities::object_data::ObjectDataCache,
|
||||||
|
|||||||
Reference in new issue
Block a user