|
|
|
@@ -1,11 +1,14 @@
|
|
|
|
|
//! Repeating continued dimensions from the latest session dimension or a picked base.
|
|
|
|
|
|
|
|
|
|
use acadrust::entities::{
|
|
|
|
|
Dimension, DimensionAngular2Ln, DimensionAngular3Pt, DimensionBase, DimensionLinear,
|
|
|
|
|
DimensionOrdinate,
|
|
|
|
|
};
|
|
|
|
|
use acadrust::types::Vector3;
|
|
|
|
|
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 glam::DVec3;
|
|
|
|
|
|
|
|
|
|
use crate::command::{CadCommand, CmdOption, CmdResult, DimensionAssociationInput};
|
|
|
|
@@ -55,25 +58,25 @@ impl SourceStyle {
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
enum ContinueKind {
|
|
|
|
|
Linear {
|
|
|
|
|
current: DVec3,
|
|
|
|
|
current: Vec2,
|
|
|
|
|
rotation: f64,
|
|
|
|
|
perpendicular: DVec3,
|
|
|
|
|
perpendicular: Vec2,
|
|
|
|
|
line_coordinate: f64,
|
|
|
|
|
},
|
|
|
|
|
Angular2Ln {
|
|
|
|
|
source: DimensionAngular2Ln,
|
|
|
|
|
vertex: DVec3,
|
|
|
|
|
current: DVec3,
|
|
|
|
|
vertex: Vec2,
|
|
|
|
|
current: Vec2,
|
|
|
|
|
radius: f64,
|
|
|
|
|
},
|
|
|
|
|
Angular3Pt {
|
|
|
|
|
source: DimensionAngular3Pt,
|
|
|
|
|
vertex: DVec3,
|
|
|
|
|
current: DVec3,
|
|
|
|
|
vertex: Vec2,
|
|
|
|
|
current: Vec2,
|
|
|
|
|
radius: f64,
|
|
|
|
|
},
|
|
|
|
|
Ordinate {
|
|
|
|
|
source: DimensionOrdinate,
|
|
|
|
|
definition: Vec2,
|
|
|
|
|
leader: Vec2,
|
|
|
|
|
is_x: bool,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -81,6 +84,7 @@ enum ContinueKind {
|
|
|
|
|
struct ContinueState {
|
|
|
|
|
kind: ContinueKind,
|
|
|
|
|
style: SourceStyle,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct DimContinueCommand {
|
|
|
|
@@ -104,78 +108,96 @@ impl DimContinueCommand {
|
|
|
|
|
command
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn install_base(&mut self, entity: &EntityType, pick: Option<DVec3>) -> bool {
|
|
|
|
|
fn install_base(&mut self, entity: &EntityType, pick_world: Option<DVec3>) -> bool {
|
|
|
|
|
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 = DVec3::new(-rotation.sin(), rotation.cos(), 0.0);
|
|
|
|
|
let current = selected_linear_end(
|
|
|
|
|
dv(source.first_point),
|
|
|
|
|
dv(source.second_point),
|
|
|
|
|
pick,
|
|
|
|
|
);
|
|
|
|
|
let perpendicular = Vec2::new(-rotation.sin(), rotation.cos());
|
|
|
|
|
ContinueKind::Linear {
|
|
|
|
|
current,
|
|
|
|
|
current: selected_linear_end(
|
|
|
|
|
project(&plane, source.first_point),
|
|
|
|
|
project(&plane, source.second_point),
|
|
|
|
|
pick,
|
|
|
|
|
),
|
|
|
|
|
rotation,
|
|
|
|
|
perpendicular,
|
|
|
|
|
line_coordinate: dv(source.base.definition_point).dot(perpendicular),
|
|
|
|
|
line_coordinate: project(&plane, source.base.definition_point)
|
|
|
|
|
.dot(perpendicular),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Dimension::Aligned(source) => {
|
|
|
|
|
let first = dv(source.first_point);
|
|
|
|
|
let second = dv(source.second_point);
|
|
|
|
|
let delta = second - first;
|
|
|
|
|
if delta.length_squared() <= 1.0e-18 {
|
|
|
|
|
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 = delta.y.atan2(delta.x);
|
|
|
|
|
let perpendicular = DVec3::new(-rotation.sin(), rotation.cos(), 0.0);
|
|
|
|
|
};
|
|
|
|
|
let rotation = direction.angle();
|
|
|
|
|
let perpendicular = direction.perpendicular();
|
|
|
|
|
ContinueKind::Linear {
|
|
|
|
|
current: selected_linear_end(first, second, pick),
|
|
|
|
|
rotation,
|
|
|
|
|
perpendicular,
|
|
|
|
|
line_coordinate: dv(source.base.definition_point).dot(perpendicular),
|
|
|
|
|
line_coordinate: project(&plane, source.base.definition_point)
|
|
|
|
|
.dot(perpendicular),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Dimension::Angular2Ln(source) => {
|
|
|
|
|
let vertex = angular2_vertex(source);
|
|
|
|
|
let first = dv(source.second_point);
|
|
|
|
|
let second = dv(source.definition_point);
|
|
|
|
|
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 {
|
|
|
|
|
source: source.clone(),
|
|
|
|
|
vertex,
|
|
|
|
|
current: selected_angular_end(first, second, pick),
|
|
|
|
|
radius: (dv(source.dimension_arc) - vertex).length().max(1.0e-9),
|
|
|
|
|
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 = dv(source.angle_vertex);
|
|
|
|
|
let vertex = project(&plane, source.angle_vertex);
|
|
|
|
|
ContinueKind::Angular3Pt {
|
|
|
|
|
source: source.clone(),
|
|
|
|
|
vertex,
|
|
|
|
|
current: selected_angular_end(
|
|
|
|
|
dv(source.first_point),
|
|
|
|
|
dv(source.second_point),
|
|
|
|
|
vertex,
|
|
|
|
|
[
|
|
|
|
|
project(&plane, source.first_point),
|
|
|
|
|
project(&plane, source.second_point),
|
|
|
|
|
],
|
|
|
|
|
pick,
|
|
|
|
|
),
|
|
|
|
|
radius: (dv(source.definition_point) - vertex).length().max(1.0e-9),
|
|
|
|
|
radius: project(&plane, source.definition_point)
|
|
|
|
|
.distance(vertex)
|
|
|
|
|
.max(1.0e-9),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Dimension::Ordinate(source) => ContinueKind::Ordinate {
|
|
|
|
|
source: source.clone(),
|
|
|
|
|
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 });
|
|
|
|
|
self.base = Some(ContinueState { kind, style, plane });
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_dimension(&self, point: DVec3) -> Option<Dimension> {
|
|
|
|
|
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,
|
|
|
|
@@ -183,6 +205,7 @@ impl DimContinueCommand {
|
|
|
|
|
perpendicular,
|
|
|
|
|
line_coordinate,
|
|
|
|
|
} => build_linear(
|
|
|
|
|
state.plane,
|
|
|
|
|
*current,
|
|
|
|
|
point,
|
|
|
|
|
*rotation,
|
|
|
|
@@ -190,78 +213,88 @@ impl DimContinueCommand {
|
|
|
|
|
*line_coordinate,
|
|
|
|
|
),
|
|
|
|
|
ContinueKind::Angular2Ln {
|
|
|
|
|
source,
|
|
|
|
|
vertex,
|
|
|
|
|
current,
|
|
|
|
|
radius,
|
|
|
|
|
} => {
|
|
|
|
|
let moving = point - *vertex;
|
|
|
|
|
let previous = *current - *vertex;
|
|
|
|
|
if moving.length_squared() <= 1.0e-18 || previous.length_squared() <= 1.0e-18 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let mut result = source.clone();
|
|
|
|
|
result.first_point = v3(*vertex);
|
|
|
|
|
result.second_point = v3(point);
|
|
|
|
|
result.angle_vertex = v3(*vertex);
|
|
|
|
|
result.definition_point = v3(*current);
|
|
|
|
|
let moving = point - *vertex;
|
|
|
|
|
let (definition, text) =
|
|
|
|
|
angular_definition_and_text(*vertex, previous, moving, *radius);
|
|
|
|
|
result.dimension_arc = v3(definition);
|
|
|
|
|
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 = v3(text);
|
|
|
|
|
result.base.text_middle_point = world(state.plane, text);
|
|
|
|
|
result.base.insertion_point = result.base.text_middle_point;
|
|
|
|
|
result.base.actual_measurement = result.measurement_degrees();
|
|
|
|
|
Dimension::Angular2Ln(result)
|
|
|
|
|
}
|
|
|
|
|
ContinueKind::Angular3Pt {
|
|
|
|
|
source,
|
|
|
|
|
vertex,
|
|
|
|
|
current,
|
|
|
|
|
radius,
|
|
|
|
|
} => {
|
|
|
|
|
let moving = point - *vertex;
|
|
|
|
|
let previous = *current - *vertex;
|
|
|
|
|
if moving.length_squared() <= 1.0e-18 || previous.length_squared() <= 1.0e-18 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let mut result = source.clone();
|
|
|
|
|
result.angle_vertex = v3(*vertex);
|
|
|
|
|
result.first_point = v3(point);
|
|
|
|
|
result.second_point = v3(*current);
|
|
|
|
|
let moving = point - *vertex;
|
|
|
|
|
let (definition, text) =
|
|
|
|
|
angular_definition_and_text(*vertex, previous, moving, *radius);
|
|
|
|
|
result.definition_point = v3(definition);
|
|
|
|
|
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 = v3(text);
|
|
|
|
|
result.base.text_middle_point = world(state.plane, text);
|
|
|
|
|
result.base.insertion_point = result.base.text_middle_point;
|
|
|
|
|
result.base.actual_measurement = result.measurement_degrees();
|
|
|
|
|
Dimension::Angular3Pt(result)
|
|
|
|
|
}
|
|
|
|
|
ContinueKind::Ordinate { source } => {
|
|
|
|
|
let source_leader = dv(source.leader_endpoint);
|
|
|
|
|
let leader = if source.is_ordinate_type_x {
|
|
|
|
|
DVec3::new(point.x, source_leader.y, source_leader.z)
|
|
|
|
|
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 {
|
|
|
|
|
DVec3::new(source_leader.x, point.y, source_leader.z)
|
|
|
|
|
Vec2::new(source_leader.x, feature.y)
|
|
|
|
|
};
|
|
|
|
|
let mut result =
|
|
|
|
|
DimensionOrdinate::new(v3(point), v3(leader), source.is_ordinate_type_x);
|
|
|
|
|
result.definition_point = source.definition_point;
|
|
|
|
|
result.base.definition_point = source.base.definition_point;
|
|
|
|
|
result.base.text_middle_point = v3(leader);
|
|
|
|
|
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;
|
|
|
|
|
result.base.actual_measurement = result.measurement();
|
|
|
|
|
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: DVec3) {
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
@@ -348,7 +381,7 @@ impl CadCommand for DimContinueCommand {
|
|
|
|
|
entity: EntityType::Dimension(dimension),
|
|
|
|
|
association: DimensionAssociationInput::Infer(None),
|
|
|
|
|
preserve_base_style: self.preserve_base_style,
|
|
|
|
|
keep_active: true,
|
|
|
|
|
continue_command: true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -393,7 +426,26 @@ impl CadCommand for DimContinueCommand {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn selected_linear_end(first: DVec3, second: DVec3, pick: Option<DVec3>) -> DVec3 {
|
|
|
|
|
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
|
|
|
|
@@ -403,112 +455,157 @@ fn selected_linear_end(first: DVec3, second: DVec3, pick: Option<DVec3>) -> DVec
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn selected_angular_end(first: DVec3, second: DVec3, pick: Option<DVec3>) -> DVec3 {
|
|
|
|
|
pick.map_or(first, |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 build_linear(
|
|
|
|
|
first: DVec3,
|
|
|
|
|
second: DVec3,
|
|
|
|
|
rotation: f64,
|
|
|
|
|
perpendicular: DVec3,
|
|
|
|
|
line_coordinate: f64,
|
|
|
|
|
) -> Dimension {
|
|
|
|
|
let first_line = first + perpendicular * (line_coordinate - first.dot(perpendicular));
|
|
|
|
|
let second_line = second + perpendicular * (line_coordinate - second.dot(perpendicular));
|
|
|
|
|
let mut result = DimensionLinear::new(v3(first), v3(second));
|
|
|
|
|
result.rotation = rotation;
|
|
|
|
|
result.definition_point = v3(second_line);
|
|
|
|
|
result.base.definition_point = v3(second_line);
|
|
|
|
|
result.base.text_middle_point = v3((first_line + second_line) * 0.5);
|
|
|
|
|
result.base.insertion_point = result.base.text_middle_point;
|
|
|
|
|
result.base.actual_measurement = result.measurement();
|
|
|
|
|
Dimension::Linear(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn angular2_vertex(source: &DimensionAngular2Ln) -> DVec3 {
|
|
|
|
|
let first = dv(source.first_point);
|
|
|
|
|
let first_direction = dv(source.second_point) - first;
|
|
|
|
|
let second = dv(source.angle_vertex);
|
|
|
|
|
let second_direction = dv(source.definition_point) - second;
|
|
|
|
|
line_intersection(first, first_direction, second, second_direction).unwrap_or(second)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn line_intersection(a: DVec3, b: DVec3, c: DVec3, d: DVec3) -> Option<DVec3> {
|
|
|
|
|
let cross = b.x * d.y - b.y * d.x;
|
|
|
|
|
if cross.abs() <= 1.0e-12 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let delta = c - a;
|
|
|
|
|
Some(a + b * ((delta.x * d.y - delta.y * d.x) / cross))
|
|
|
|
|
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: DVec3,
|
|
|
|
|
previous: DVec3,
|
|
|
|
|
moving: DVec3,
|
|
|
|
|
vertex: Vec2,
|
|
|
|
|
previous: Vec2,
|
|
|
|
|
moving: Vec2,
|
|
|
|
|
radius: f64,
|
|
|
|
|
) -> (DVec3, DVec3) {
|
|
|
|
|
let start = previous.y.atan2(previous.x);
|
|
|
|
|
let mut sweep = moving.y.atan2(moving.x) - start;
|
|
|
|
|
while sweep <= -std::f64::consts::PI {
|
|
|
|
|
sweep += std::f64::consts::TAU;
|
|
|
|
|
) -> 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;
|
|
|
|
|
}
|
|
|
|
|
while sweep > std::f64::consts::PI {
|
|
|
|
|
sweep -= std::f64::consts::TAU;
|
|
|
|
|
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(),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
let point_at = |fraction: f64| {
|
|
|
|
|
let angle = start + sweep * fraction;
|
|
|
|
|
vertex + DVec3::new(angle.cos(), angle.sin(), 0.0) * radius
|
|
|
|
|
};
|
|
|
|
|
(point_at(2.0 / 3.0), point_at(0.5))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn preview_for_dimension(dimension: &Dimension) -> WireModel {
|
|
|
|
|
let mut points = Vec::<[f64; 3]>::new();
|
|
|
|
|
match dimension {
|
|
|
|
|
Dimension::Linear(dimension) => linear_preview(
|
|
|
|
|
&mut points,
|
|
|
|
|
dv(dimension.first_point),
|
|
|
|
|
dv(dimension.second_point),
|
|
|
|
|
dimension.rotation,
|
|
|
|
|
dv(dimension.definition_point),
|
|
|
|
|
dv(dimension.base.text_middle_point),
|
|
|
|
|
dimension.base.actual_measurement,
|
|
|
|
|
),
|
|
|
|
|
Dimension::Angular2Ln(dimension) => {
|
|
|
|
|
let vertex = angular2_vertex(dimension);
|
|
|
|
|
angular_preview(
|
|
|
|
|
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,
|
|
|
|
|
dv(dimension.second_point) - vertex,
|
|
|
|
|
dv(dimension.definition_point) - vertex,
|
|
|
|
|
dv(dimension.dimension_arc),
|
|
|
|
|
dv(dimension.base.text_middle_point),
|
|
|
|
|
dimension.base.actual_measurement,
|
|
|
|
|
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,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
Dimension::Angular3Pt(dimension) => angular_preview(
|
|
|
|
|
&mut points,
|
|
|
|
|
dv(dimension.angle_vertex),
|
|
|
|
|
dv(dimension.first_point) - dv(dimension.angle_vertex),
|
|
|
|
|
dv(dimension.second_point) - dv(dimension.angle_vertex),
|
|
|
|
|
dv(dimension.definition_point),
|
|
|
|
|
dv(dimension.base.text_middle_point),
|
|
|
|
|
dimension.base.actual_measurement,
|
|
|
|
|
),
|
|
|
|
|
Dimension::Ordinate(dimension) => ordinate_preview(
|
|
|
|
|
&mut points,
|
|
|
|
|
dv(dimension.feature_location),
|
|
|
|
|
dv(dimension.leader_endpoint),
|
|
|
|
|
dimension.base.actual_measurement,
|
|
|
|
|
),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
WireModel::solid_f64(
|
|
|
|
@@ -521,103 +618,166 @@ fn preview_for_dimension(dimension: &Dimension) -> WireModel {
|
|
|
|
|
|
|
|
|
|
fn linear_preview(
|
|
|
|
|
points: &mut Vec<[f64; 3]>,
|
|
|
|
|
first: DVec3,
|
|
|
|
|
second: DVec3,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
first: Vec2,
|
|
|
|
|
second: Vec2,
|
|
|
|
|
rotation: f64,
|
|
|
|
|
definition: DVec3,
|
|
|
|
|
text: DVec3,
|
|
|
|
|
definition: Vec2,
|
|
|
|
|
text: Vec2,
|
|
|
|
|
measurement: f64,
|
|
|
|
|
) {
|
|
|
|
|
let axis = DVec3::new(rotation.cos(), rotation.sin(), 0.0);
|
|
|
|
|
let perpendicular = DVec3::new(-axis.y, axis.x, 0.0);
|
|
|
|
|
let axis = Vec2::new(rotation.cos(), rotation.sin());
|
|
|
|
|
let perpendicular = axis.perpendicular();
|
|
|
|
|
let coordinate = definition.dot(perpendicular);
|
|
|
|
|
let first_line = first + perpendicular * (coordinate - first.dot(perpendicular));
|
|
|
|
|
let second_line = second + perpendicular * (coordinate - second.dot(perpendicular));
|
|
|
|
|
segment(points, first, first_line);
|
|
|
|
|
segment(points, second, second_line);
|
|
|
|
|
segment(points, first_line, second_line);
|
|
|
|
|
arrow(points, first_line, axis, perpendicular, first_line.distance(second_line));
|
|
|
|
|
arrow(points, second_line, -axis, perpendicular, first_line.distance(second_line));
|
|
|
|
|
text_box(points, text, axis, perpendicular, measurement);
|
|
|
|
|
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]>,
|
|
|
|
|
vertex: DVec3,
|
|
|
|
|
first: DVec3,
|
|
|
|
|
second: DVec3,
|
|
|
|
|
arc_point: DVec3,
|
|
|
|
|
text: DVec3,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
vertex: Vec2,
|
|
|
|
|
first: Vec2,
|
|
|
|
|
second: Vec2,
|
|
|
|
|
arc_point: Vec2,
|
|
|
|
|
text: Vec2,
|
|
|
|
|
measurement: f64,
|
|
|
|
|
) {
|
|
|
|
|
let radius = (arc_point - vertex).length().max(1.0e-9);
|
|
|
|
|
let start = first.y.atan2(first.x);
|
|
|
|
|
let mut sweep = second.y.atan2(second.x) - start;
|
|
|
|
|
while sweep <= -std::f64::consts::PI {
|
|
|
|
|
sweep += std::f64::consts::TAU;
|
|
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
while sweep > std::f64::consts::PI {
|
|
|
|
|
sweep -= std::f64::consts::TAU;
|
|
|
|
|
}
|
|
|
|
|
let first_end = vertex + normalized_or(first, DVec3::X) * radius;
|
|
|
|
|
let second_end = vertex + normalized_or(second, DVec3::Y) * radius;
|
|
|
|
|
segment(points, vertex, first_end);
|
|
|
|
|
segment(points, vertex, second_end);
|
|
|
|
|
let arc = cadkernel::geom2d::tessellate::arc(
|
|
|
|
|
[vertex.x, vertex.y],
|
|
|
|
|
radius,
|
|
|
|
|
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 + sweep,
|
|
|
|
|
vertex.z,
|
|
|
|
|
cadkernel::geom2d::tessellate::DEFAULT_SEGMENTS_PER_RADIAN,
|
|
|
|
|
(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,
|
|
|
|
|
);
|
|
|
|
|
points.extend(arc);
|
|
|
|
|
points.push([f64::NAN, f64::NAN, f64::NAN]);
|
|
|
|
|
let sign = sweep.signum();
|
|
|
|
|
let start_tangent = DVec3::new(-start.sin(), start.cos(), 0.0) * sign;
|
|
|
|
|
let end_angle = start + sweep;
|
|
|
|
|
let end_tangent = DVec3::new(end_angle.sin(), -end_angle.cos(), 0.0) * sign;
|
|
|
|
|
arrow(points, first_end, start_tangent, normalized_or(first, DVec3::X), radius);
|
|
|
|
|
arrow(points, second_end, end_tangent, normalized_or(second, DVec3::Y), radius);
|
|
|
|
|
let middle = start + sweep * 0.5;
|
|
|
|
|
let text_axis = normalized_or(DVec3::new(-middle.sin(), middle.cos(), 0.0), DVec3::X);
|
|
|
|
|
let text_perpendicular = DVec3::new(-text_axis.y, text_axis.x, 0.0);
|
|
|
|
|
text_box(points, text, text_axis, text_perpendicular, measurement);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ordinate_preview(
|
|
|
|
|
points: &mut Vec<[f64; 3]>,
|
|
|
|
|
feature: DVec3,
|
|
|
|
|
leader: DVec3,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
feature: Vec2,
|
|
|
|
|
leader: Vec2,
|
|
|
|
|
measurement: f64,
|
|
|
|
|
) {
|
|
|
|
|
segment(points, feature, leader);
|
|
|
|
|
let axis = normalized_or(leader - feature, DVec3::Y);
|
|
|
|
|
let perpendicular = DVec3::new(-axis.y, axis.x, 0.0);
|
|
|
|
|
arrow(points, feature, axis, perpendicular, feature.distance(leader));
|
|
|
|
|
text_box(points, leader, perpendicular, axis, measurement);
|
|
|
|
|
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]>,
|
|
|
|
|
tip: DVec3,
|
|
|
|
|
inward: DVec3,
|
|
|
|
|
perpendicular: DVec3,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
tip: Vec2,
|
|
|
|
|
inward: Vec2,
|
|
|
|
|
perpendicular: Vec2,
|
|
|
|
|
span: f64,
|
|
|
|
|
) {
|
|
|
|
|
let inward = normalized_or(inward, DVec3::X);
|
|
|
|
|
let perpendicular = normalized_or(perpendicular, DVec3::Y);
|
|
|
|
|
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, tip, back + perpendicular * size * 0.4);
|
|
|
|
|
segment(points, tip, back - perpendicular * size * 0.4);
|
|
|
|
|
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]>,
|
|
|
|
|
center: DVec3,
|
|
|
|
|
axis: DVec3,
|
|
|
|
|
perpendicular: DVec3,
|
|
|
|
|
plane: Plane,
|
|
|
|
|
center: Vec2,
|
|
|
|
|
axis: Vec2,
|
|
|
|
|
perpendicular: Vec2,
|
|
|
|
|
measurement: f64,
|
|
|
|
|
) {
|
|
|
|
|
let digits = if measurement.abs() < 1.0 {
|
|
|
|
@@ -631,30 +791,51 @@ fn text_box(
|
|
|
|
|
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;
|
|
|
|
|
points.extend([a.to_array(), b.to_array(), c.to_array(), d.to_array(), a.to_array()]);
|
|
|
|
|
points.push([f64::NAN, f64::NAN, f64::NAN]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn segment(points: &mut Vec<[f64; 3]>, first: DVec3, second: DVec3) {
|
|
|
|
|
points.push(first.to_array());
|
|
|
|
|
points.push(second.to_array());
|
|
|
|
|
points.push([f64::NAN, f64::NAN, f64::NAN]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn normalized_or(value: DVec3, fallback: DVec3) -> DVec3 {
|
|
|
|
|
if value.length_squared() > 1.0e-18 {
|
|
|
|
|
value.normalize()
|
|
|
|
|
} else {
|
|
|
|
|
fallback
|
|
|
|
|
for point in [a, b, c, d, a] {
|
|
|
|
|
push_local(points, plane, point);
|
|
|
|
|
}
|
|
|
|
|
points.push([f64::NAN; 3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn dv(point: Vector3) -> DVec3 {
|
|
|
|
|
DVec3::new(point.x, point.y, point.z)
|
|
|
|
|
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 v3(point: DVec3) -> Vector3 {
|
|
|
|
|
Vector3::new(point.x, point.y, point.z)
|
|
|
|
|
fn plane_from_normal(origin: Vector3, normal: Vector3) -> Plane {
|
|
|
|
|
let (x_axis, y_axis) =
|
|
|
|
|
crate::scene::view::transform::ocs_axes((normal.x, normal.y, normal.z));
|
|
|
|
|
Plane::from_axes(
|
|
|
|
|
point(origin),
|
|
|
|
|
[x_axis.0, x_axis.1, x_axis.2],
|
|
|
|
|
[y_axis.0, y_axis.1, y_axis.2],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn project(plane: &Plane, value: Vector3) -> Vec2 {
|
|
|
|
|
Vec2::from(plane.project(point(value)).unwrap_or([0.0; 2]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn world(plane: Plane, value: Vec2) -> Vector3 {
|
|
|
|
|
let value = plane.point_at(value.into());
|
|
|
|
|
Vector3::new(value[0], value[1], value[2])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn point(value: Vector3) -> [f64; 3] {
|
|
|
|
|
[value.x, value.y, value.z]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn segment(points: &mut Vec<[f64; 3]>, plane: Plane, first: Vec2, second: Vec2) {
|
|
|
|
|
push_local(points, plane, first);
|
|
|
|
|
push_local(points, plane, second);
|
|
|
|
|
points.push([f64::NAN; 3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn push_local(points: &mut Vec<[f64; 3]>, plane: Plane, point: Vec2) {
|
|
|
|
|
points.push(plane.point_at(point.into()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inventory::submit!(crate::command::CommandRegistration { names: &["DIMCONTINUE"] });
|