fix: pivot pinning and origin angle

This commit is contained in:
mtvare6 2025-07-06 12:30:57 +05:30
parent a0115ff54e
commit ba31408f87
5 changed files with 70 additions and 32 deletions

View file

@ -1,8 +1,7 @@
use super::utility_functions::overlay_canvas_context;
use crate::consts::{
COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_ORANGE, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE,
COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH,
PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER,
COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
};
use crate::messages::prelude::Message;
use bezier_rs::{Bezier, Subpath};
@ -559,9 +558,9 @@ impl OverlayContext {
self.end_dpi_aware_transform();
}
pub fn dowel_pin(&mut self, position: DVec2, color: Option<&str>) {
pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) {
let (x, y) = (position.round() - DVec2::splat(0.5)).into();
let color = color.unwrap_or(COLOR_OVERLAY_ORANGE);
let color = color.unwrap_or(COLOR_OVERLAY_YELLOW);
self.start_dpi_aware_transform();
@ -577,11 +576,11 @@ impl OverlayContext {
self.render_context.begin_path();
// Top-left sector
self.render_context.move_to(x, y);
self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2, PI).expect("Failed to draw arc");
self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2 + angle, PI + angle).expect("Failed to draw arc");
self.render_context.close_path();
// Bottom-right sector
self.render_context.move_to(x, y);
self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2, TAU).expect("Failed to draw arc");
self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2 + angle, TAU + angle).expect("Failed to draw arc");
self.render_context.close_path();
self.render_context.set_fill_style_str(color);
self.render_context.fill();

View file

@ -171,6 +171,8 @@ pub struct Pivot {
active: bool,
/// Used to enable and disable the pivot
pub pinned: bool,
/// Had selected_visible_and_unlocked_layers
pub empty: bool,
}
impl Default for Pivot {
@ -183,6 +185,7 @@ impl Default for Pivot {
last_non_none_reference: ReferencePoint::Center,
active: true,
pinned: false,
empty: true,
}
}
}
@ -195,9 +198,9 @@ impl Pivot {
}
let selected = document.network_interface.selected_nodes();
self.empty = !selected.has_selected_nodes();
if !selected.has_selected_nodes() {
self.normalized_pivot = DVec2::splat(0.5);
self.pivot = None;
return;
};
@ -221,7 +224,9 @@ impl Pivot {
let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]);
self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
if self.old_pivot_position != ReferencePoint::None {
self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
}
}
pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, bounds: Option<[DVec2; 2]>) {

View file

@ -263,15 +263,15 @@ impl LayoutHolder for PathTool {
.selected_index(Some(self.options.path_overlay_mode as u32))
.widget_holder();
let [checkbox, dropdown] = {
let [_checkbox, _dropdown] = {
let dot_widget = dot_type_widget(self.tool_data.dot.state, Source::Path);
[dot_widget.get(0).unwrap().clone(), dot_widget.get(2).unwrap().clone()]
[dot_widget[0].clone(), dot_widget[2].clone()]
};
let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty();
let pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path);
let _pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path);
let pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path);
let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path);
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
widgets: vec![
@ -289,13 +289,13 @@ impl LayoutHolder for PathTool {
unrelated_seperator.clone(),
path_overlay_mode_widget,
unrelated_seperator.clone(),
checkbox.clone(),
related_seperator.clone(),
dropdown.clone(),
unrelated_seperator,
pivot_reference,
related_seperator.clone(),
pin_pivot,
// checkbox.clone(),
// related_seperator.clone(),
// dropdown.clone(),
// unrelated_seperator,
// pivot_reference,
// related_seperator.clone(),
// pin_pivot,
],
}]))
}
@ -566,7 +566,6 @@ impl PathToolData {
fn update_selection_status(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) {
let selection_status = get_selection_status(&document.network_interface, shape_editor);
// debug!("{:?}", selection_status);
self.can_toggle_colinearity = match &selection_status {
SelectionStatus::None => false,
@ -610,8 +609,6 @@ impl PathToolData {
let old_selection = shape_editor.selected_points().cloned().collect::<Vec<_>>();
debug!("{old_selection:?}");
// Check if the point is already selected; if not, select the first point within the threshold (in pixels)
// Don't select the points which are not shown currently in PathOverlayMode
if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state(
@ -1396,6 +1393,10 @@ impl Fsm for PathToolFsmState {
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options);
let ToolMessage::Path(event) = event else { return self };
// TODO(mTvare6): Remove it once dots are implemented for path_tool
tool_data.dot.state.enabled = false;
match (self, event) {
(_, PathToolMessage::SelectionChanged) => {
// Set the newly targeted layers to visible

View file

@ -538,7 +538,7 @@ impl SelectToolData {
fn state_from_dot(&self, mouse: DVec2) -> Option<SelectToolFsmState> {
match self.dot.state.dot {
DotType::Pivot if !self.dot.pivot.pinned => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot),
DotType::Pivot => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot),
_ => None,
}
}
@ -766,21 +766,52 @@ impl Fsm for SelectToolFsmState {
});
let mut active_origin = None;
let mut origin_angle = 0.;
if overlay_context.visibility_settings.origin() && !tool_data.dot.state.is_pivot_type() {
let get_angle = |layer: LayerNodeIdentifier| -> f64 {
let quad = Quad::from_box([DVec2::ZERO, DVec2::ONE]);
let bounds = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface) * quad;
(bounds.top_left() - bounds.top_right()).to_angle()
};
if tool_data.dot.state.dot == DotType::Average {
let mut count = 0;
let sum: f64 = document
.network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(&document.network_interface)
.map(get_angle)
.inspect(|_| count += 1)
.sum();
if count > 0 {
origin_angle = sum / count as f64;
}
} else if tool_data.dot.state.dot == DotType::Active {
origin_angle = document
.network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(&document.network_interface)
.find(|&layer| Some(layer) == tool_data.dot.layer)
.iter()
.map(|&layer| get_angle(layer))
.sum();
}
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface);
if Some(layer) == tool_data.dot.layer {
active_origin = Some(origin);
continue;
}
overlay_context.dowel_pin(origin, None);
overlay_context.dowel_pin(origin, origin_angle, None);
}
}
if let Some(origin) = active_origin {
overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_YELLOW));
overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_ORANGE));
}
let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot();
let has_layers = document.network_interface.selected_nodes().has_selected_nodes();
let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers;
tool_data.dot.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot);
// Update compass rose
@ -1009,8 +1040,10 @@ impl Fsm for SelectToolFsmState {
let extend = input.keyboard.key(extend_selection);
if !extend && !input.keyboard.key(remove_from_selection) {
responses.add(DocumentMessage::DeselectAllLayers);
let position = tool_data.dot.pivot.last_non_none_reference;
responses.add(SelectToolMessage::SetPivot { position });
if !tool_data.dot.pivot.pinned {
let position = tool_data.dot.pivot.last_non_none_reference;
responses.add(SelectToolMessage::SetPivot { position });
}
tool_data.layers_dragging.clear();
}

View file

@ -388,8 +388,8 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
}
}
if let Some(bounds) = self.path_bounds {
overlay_context.quad(Quad::from_box(bounds), None, None);
if let Some(_) = self.path_bounds {
// overlay_context.quad(Quad::from_box(bounds), None, None);
}
}