Refactor collection of snap targets (#2114)
* Collect snap targets cleanup * Make Clippy happy --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
d7a271f675
commit
51ce51ea8c
|
|
@ -30,6 +30,9 @@ pub const DRAG_BEYOND_VIEWPORT_SPEED_FACTOR: f64 = 20.;
|
|||
|
||||
// Snapping point
|
||||
pub const SNAP_POINT_TOLERANCE: f64 = 5.;
|
||||
pub const MAX_ALIGNMENT_CANDIDATES: usize = 100; // These are layers whose bounding boxes are used for alignment.
|
||||
pub const MAX_SNAP_CANDIDATES: usize = 10; // These are layers that are used for the layer snapper
|
||||
pub const MAX_LAYER_SNAP_POINTS: usize = 100; // These are points (anchors and bounding box corners etc.) in the layer snapper
|
||||
|
||||
pub const DRAG_THRESHOLD: f64 = 1.;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::messages::tool::common_functionality::snapping::SnapManager;
|
|||
use crate::messages::{input_mapper::utility_types::input_keyboard::Key, portfolio::document::graph_operation::utility_types::TransformIn};
|
||||
use glam::{DAffine2, DVec2, Vec2Swizzles};
|
||||
|
||||
use super::snapping::{SnapCandidatePoint, SnapConstraint, SnapData};
|
||||
use super::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapTypeConfiguration};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Resize {
|
||||
|
|
@ -19,7 +19,7 @@ impl Resize {
|
|||
pub fn start(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
||||
let root_transform = document.metadata().document_to_viewport;
|
||||
let point = SnapCandidatePoint::handle(root_transform.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
self.drag_start = snapped.snapped_point_document;
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +51,7 @@ impl Resize {
|
|||
let ratio = input.keyboard.get(lock_ratio as usize);
|
||||
let center = input.keyboard.get(center as usize);
|
||||
let snap_data = SnapData::ignore(document, input, &ignore);
|
||||
let config = SnapTypeConfiguration::default();
|
||||
if ratio {
|
||||
let size = points_viewport[1] - points_viewport[0];
|
||||
let size = size.abs().max(size.abs().yx()) * size.signum();
|
||||
|
|
@ -61,27 +62,28 @@ impl Resize {
|
|||
direction: end_document - self.drag_start,
|
||||
};
|
||||
if center {
|
||||
let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, None);
|
||||
let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, config);
|
||||
let far = SnapCandidatePoint::handle(2. * self.drag_start - end_document);
|
||||
let snapped_far = self.snap_manager.constrained_snap(&snap_data, &far, constraint, None);
|
||||
let snapped_far = self.snap_manager.constrained_snap(&snap_data, &far, constraint, config);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
self.snap_manager.update_indicator(best);
|
||||
} else {
|
||||
let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, None);
|
||||
let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, config);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
self.snap_manager.update_indicator(snapped);
|
||||
}
|
||||
} else if center {
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), None, false);
|
||||
let snapped_far = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(2. * self.drag_start - document_mouse), None, false);
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config);
|
||||
let opposite = 2. * self.drag_start - document_mouse;
|
||||
let snapped_far = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(opposite), config);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
self.snap_manager.update_indicator(best);
|
||||
} else {
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), None, false);
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
self.snap_manager.update_indicator(snapped);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc
|
|||
use crate::messages::portfolio::document::utility_types::misc::{GeometrySnapSource, SnapSource};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;
|
||||
use crate::messages::tool::tool_messages::path_tool::PointSelectState;
|
||||
|
||||
use bezier_rs::{Bezier, BezierHandles, TValue};
|
||||
|
|
@ -210,7 +211,7 @@ impl ShapeState {
|
|||
}
|
||||
}
|
||||
|
||||
let snapped = snap_manager.free_snap(&snap_data, &point, None, false);
|
||||
let snapped = snap_manager.free_snap(&snap_data, &point, SnapTypeConfiguration::default());
|
||||
if best_snapped.other_snap_better(&snapped) {
|
||||
offset = snapped.snapped_point_document - point.document_point + mouse_delta;
|
||||
best_snapped = snapped;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@ use glam::{DAffine2, DVec2};
|
|||
use graphene_std::vector::NoHashBuilder;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// Configuration for the relevant snap type
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct SnapTypeConfiguration {
|
||||
pub only_geometry: bool,
|
||||
pub use_existing_candidates: bool,
|
||||
pub accept_distribution: bool,
|
||||
pub bbox: Option<Rect>,
|
||||
}
|
||||
|
||||
/// Handles snapping and snap overlays
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SnapManager {
|
||||
|
|
@ -242,7 +251,7 @@ impl SnapManager {
|
|||
}
|
||||
pub fn preview_draw(&mut self, snap_data: &SnapData, mouse: DVec2) {
|
||||
let point = SnapCandidatePoint::handle(snap_data.document.metadata().document_to_viewport.inverse().transform_point2(mouse));
|
||||
let snapped = self.free_snap(snap_data, &point, None, false);
|
||||
let snapped = self.free_snap(snap_data, &point, SnapTypeConfiguration::default());
|
||||
self.update_indicator(snapped);
|
||||
}
|
||||
|
||||
|
|
@ -342,64 +351,64 @@ impl SnapManager {
|
|||
self.add_candidates(layer, snap_data, quad);
|
||||
}
|
||||
|
||||
if self.alignment_candidates.as_ref().is_some_and(|candidates| candidates.len() > 100) {
|
||||
if self.alignment_candidates.as_ref().is_some_and(|candidates| candidates.len() > crate::consts::MAX_ALIGNMENT_CANDIDATES) {
|
||||
warn!("Alignment candidate overflow");
|
||||
}
|
||||
if self.candidates.as_ref().is_some_and(|candidates| candidates.len() > 10) {
|
||||
if self.candidates.as_ref().is_some_and(|candidates| candidates.len() > crate::consts::MAX_SNAP_CANDIDATES) {
|
||||
warn!("Snap candidate overflow");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, bbox: Option<Rect>, to_paths: bool) -> SnappedPoint {
|
||||
pub fn free_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, config: SnapTypeConfiguration) -> SnappedPoint {
|
||||
if !point.document_point.is_finite() {
|
||||
warn!("Snapping non-finite position");
|
||||
return SnappedPoint::infinite_snap(DVec2::ZERO);
|
||||
}
|
||||
|
||||
let mut snap_results = SnapResults::default();
|
||||
if point.source_index == 0 {
|
||||
if !config.use_existing_candidates {
|
||||
self.candidates = None;
|
||||
}
|
||||
|
||||
let mut snap_data = snap_data.clone();
|
||||
if snap_data.candidates.is_none() {
|
||||
self.find_candidates(&snap_data, point, bbox);
|
||||
self.find_candidates(&snap_data, point, config.bbox);
|
||||
}
|
||||
snap_data.candidates = self.candidates.as_ref();
|
||||
snap_data.alignment_candidates = self.alignment_candidates.as_ref();
|
||||
|
||||
self.layer_snapper.free_snap(&mut snap_data, point, &mut snap_results);
|
||||
self.layer_snapper.free_snap(&mut snap_data, point, &mut snap_results, config);
|
||||
self.grid_snapper.free_snap(&mut snap_data, point, &mut snap_results);
|
||||
self.alignment_snapper.free_snap(&mut snap_data, point, &mut snap_results);
|
||||
self.distribution_snapper.free_snap(&mut snap_data, point, &mut snap_results, bbox);
|
||||
self.alignment_snapper.free_snap(&mut snap_data, point, &mut snap_results, config);
|
||||
self.distribution_snapper.free_snap(&mut snap_data, point, &mut snap_results, config);
|
||||
|
||||
Self::find_best_snap(&mut snap_data, point, snap_results, false, false, to_paths)
|
||||
Self::find_best_snap(&mut snap_data, point, snap_results, false, false, config.only_geometry)
|
||||
}
|
||||
|
||||
pub fn constrained_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, constraint: SnapConstraint, bbox: Option<Rect>) -> SnappedPoint {
|
||||
pub fn constrained_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, constraint: SnapConstraint, config: SnapTypeConfiguration) -> SnappedPoint {
|
||||
if !point.document_point.is_finite() {
|
||||
warn!("Snapping non-finite position");
|
||||
return SnappedPoint::infinite_snap(DVec2::ZERO);
|
||||
}
|
||||
|
||||
let mut snap_results = SnapResults::default();
|
||||
if point.source_index == 0 {
|
||||
if !config.use_existing_candidates {
|
||||
self.candidates = None;
|
||||
}
|
||||
|
||||
let mut snap_data = snap_data.clone();
|
||||
if snap_data.candidates.is_none() {
|
||||
self.find_candidates(&snap_data, point, bbox);
|
||||
self.find_candidates(&snap_data, point, config.bbox);
|
||||
}
|
||||
snap_data.candidates = self.candidates.as_ref();
|
||||
snap_data.alignment_candidates = self.alignment_candidates.as_ref();
|
||||
|
||||
self.layer_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint);
|
||||
self.layer_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config);
|
||||
self.grid_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint);
|
||||
self.alignment_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint);
|
||||
self.distribution_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, bbox);
|
||||
self.alignment_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config);
|
||||
self.distribution_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config);
|
||||
|
||||
Self::find_best_snap(&mut snap_data, point, snap_results, true, false, false)
|
||||
Self::find_best_snap(&mut snap_data, point, snap_results, true, false, config.only_geometry)
|
||||
}
|
||||
|
||||
fn alignment_x_overlay(boxes: &VecDeque<Rect>, transform: DAffine2, overlay_context: &mut OverlayContext) {
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ impl AlignmentSnapper {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn snap_bbox_points(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint) {
|
||||
self.collect_bounding_box_points(snap_data, point.source_index == 0);
|
||||
pub fn snap_bbox_points(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) {
|
||||
self.collect_bounding_box_points(snap_data, !config.use_existing_candidates);
|
||||
let unselected_geometry = if snap_data.document.snapping_state.target_enabled(SnapTarget::Alignment(AlignmentSnapTarget::Handle)) {
|
||||
snap_data.node_snap_cache.map(|cache| cache.unselected.as_slice()).unwrap_or(&[])
|
||||
} else {
|
||||
|
|
@ -154,23 +154,23 @@ impl AlignmentSnapper {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults) {
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) {
|
||||
let is_bbox = matches!(point.source, SnapSource::BoundingBox(_));
|
||||
let is_geometry = matches!(point.source, SnapSource::Geometry(_));
|
||||
let geometry_selected = snap_data.has_manipulators();
|
||||
|
||||
if is_bbox || (is_geometry && geometry_selected) || (is_geometry && point.alignment) {
|
||||
self.snap_bbox_points(snap_data, point, snap_results, SnapConstraint::None);
|
||||
self.snap_bbox_points(snap_data, point, snap_results, SnapConstraint::None, config);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint) {
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) {
|
||||
let is_bbox = matches!(point.source, SnapSource::BoundingBox(_));
|
||||
let is_geometry = matches!(point.source, SnapSource::Geometry(_));
|
||||
let geometry_selected = snap_data.has_manipulators();
|
||||
|
||||
if is_bbox || (is_geometry && geometry_selected) || (is_geometry && point.alignment) {
|
||||
self.snap_bbox_points(snap_data, point, snap_results, constraint);
|
||||
self.snap_bbox_points(snap_data, point, snap_results, constraint, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,22 +323,23 @@ impl DistributionSnapper {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, bounds: Option<Rect>) {
|
||||
let Some(bounds) = bounds else { return };
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) {
|
||||
let Some(bounds) = config.bbox else { return };
|
||||
if point.source != SnapSource::BoundingBox(BoundingBoxSnapSource::Center) || !snap_data.document.snapping_state.bounds.distribute {
|
||||
return;
|
||||
}
|
||||
|
||||
self.collect_bounding_box_points(snap_data, point.source_index == 0, bounds);
|
||||
self.collect_bounding_box_points(snap_data, config.accept_distribution, bounds);
|
||||
self.snap_bbox_points(snap_tolerance(snap_data.document), point, snap_results, SnapConstraint::None, bounds);
|
||||
}
|
||||
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, bounds: Option<Rect>) {
|
||||
let Some(bounds) = bounds else { return };
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) {
|
||||
let Some(bounds) = config.bbox else { return };
|
||||
if point.source != SnapSource::BoundingBox(BoundingBoxSnapSource::Center) || !snap_data.document.snapping_state.bounds.distribute {
|
||||
return;
|
||||
}
|
||||
self.collect_bounding_box_points(snap_data, point.source_index == 0, bounds);
|
||||
|
||||
self.collect_bounding_box_points(snap_data, config.accept_distribution, bounds);
|
||||
self.snap_bbox_points(snap_tolerance(snap_data.document), point, snap_results, constraint, bounds);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ impl LayerSnapper {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn free_snap_paths(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults) {
|
||||
self.collect_paths(snap_data, point.source_index == 0);
|
||||
pub fn free_snap_paths(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) {
|
||||
self.collect_paths(snap_data, !config.use_existing_candidates);
|
||||
|
||||
let document = snap_data.document;
|
||||
let normals = document.snapping_state.target_enabled(SnapTarget::Geometry(GeometrySnapTarget::Normal));
|
||||
|
|
@ -131,9 +131,9 @@ impl LayerSnapper {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn snap_paths_constrained(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint) {
|
||||
pub fn snap_paths_constrained(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) {
|
||||
let document = snap_data.document;
|
||||
self.collect_paths(snap_data, point.source_index == 0);
|
||||
self.collect_paths(snap_data, !config.use_existing_candidates);
|
||||
|
||||
let tolerance = snap_tolerance(document);
|
||||
let constraint_path = if let SnapConstraint::Circle { center, radius } = constraint {
|
||||
|
|
@ -182,6 +182,10 @@ impl LayerSnapper {
|
|||
if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) {
|
||||
continue;
|
||||
}
|
||||
if self.points_to_snap.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||
warn!("Snap point overflow; skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if document.snapping_state.target_enabled(SnapTarget::Artboard(ArtboardSnapTarget::Corner)) {
|
||||
let Some(bounds) = document
|
||||
|
|
@ -201,6 +205,10 @@ impl LayerSnapper {
|
|||
if snap_data.ignore_bounds(layer) {
|
||||
continue;
|
||||
}
|
||||
if self.points_to_snap.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||
warn!("Snap point overflow; skipping.");
|
||||
return;
|
||||
}
|
||||
let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -210,7 +218,6 @@ impl LayerSnapper {
|
|||
}
|
||||
}
|
||||
pub fn snap_anchors(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, c: SnapConstraint, constrained_point: DVec2) {
|
||||
self.collect_anchors(snap_data, point.source_index == 0);
|
||||
let mut best = None;
|
||||
for candidate in &self.points_to_snap {
|
||||
// Candidate is not on constraint
|
||||
|
|
@ -244,14 +251,16 @@ impl LayerSnapper {
|
|||
snap_results.points.push(result);
|
||||
}
|
||||
}
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults) {
|
||||
pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) {
|
||||
self.collect_anchors(snap_data, !config.use_existing_candidates);
|
||||
self.snap_anchors(snap_data, point, snap_results, SnapConstraint::None, point.document_point);
|
||||
self.free_snap_paths(snap_data, point, snap_results);
|
||||
self.free_snap_paths(snap_data, point, snap_results, config);
|
||||
}
|
||||
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint) {
|
||||
pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) {
|
||||
self.collect_anchors(snap_data, !config.use_existing_candidates);
|
||||
self.snap_anchors(snap_data, point, snap_results, constraint, constraint.projection(point.document_point));
|
||||
self.snap_paths_constrained(snap_data, point, snap_results, constraint);
|
||||
self.snap_paths_constrained(snap_data, point, snap_results, constraint, config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +322,6 @@ pub struct SnapCandidatePoint {
|
|||
pub document_point: DVec2,
|
||||
pub source: SnapSource,
|
||||
pub target: SnapTarget,
|
||||
pub source_index: usize,
|
||||
pub quad: Option<Quad>,
|
||||
pub neighbors: Vec<DVec2>,
|
||||
pub alignment: bool,
|
||||
|
|
@ -417,6 +425,9 @@ fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath<Poin
|
|||
if snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[index].id) || snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[(index + 1) % subpath.len()].id) {
|
||||
continue;
|
||||
}
|
||||
if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||
return;
|
||||
}
|
||||
|
||||
let in_handle = curve.handle_start().map(|handle| handle - curve.start).filter(handle_not_under(to_document));
|
||||
let out_handle = curve.handle_end().map(|handle| handle - curve.end).filter(handle_not_under(to_document));
|
||||
|
|
@ -435,6 +446,10 @@ fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath<Poin
|
|||
continue;
|
||||
}
|
||||
|
||||
if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||
return;
|
||||
}
|
||||
|
||||
let colinear = are_manipulator_handles_colinear(group, to_document, subpath, index);
|
||||
|
||||
if colinear && document.snapping_state.target_enabled(SnapTarget::Geometry(GeometrySnapTarget::AnchorWithColinearHandles)) {
|
||||
|
|
@ -471,6 +486,9 @@ pub fn get_layer_snap_points(layer: LayerNodeIdentifier, snap_data: &SnapData, p
|
|||
if document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||
return;
|
||||
}
|
||||
if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||
return;
|
||||
}
|
||||
|
||||
if layer.has_children(document.metadata()) {
|
||||
for child in layer.descendants(document.metadata()) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use crate::messages::frontend::utility_types::MouseCursorIcon;
|
|||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;
|
||||
|
||||
use graphene_core::renderer::Quad;
|
||||
|
||||
|
|
@ -124,7 +125,15 @@ impl SelectedEdges {
|
|||
let mut best_snap = SnappedPoint::infinite_snap(pivot);
|
||||
let mut best_scale_factor = DVec2::ONE;
|
||||
let tolerance = snapping::snap_tolerance(snap_data.document);
|
||||
for point in points {
|
||||
|
||||
let bbox = Some(Rect::from_box((bounds_to_doc * Quad::from_box([min, max])).bounding_box()));
|
||||
for (index, point) in points.iter_mut().enumerate() {
|
||||
let config = SnapTypeConfiguration {
|
||||
bbox,
|
||||
use_existing_candidates: index != 0,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let old_position = point.document_point;
|
||||
let bounds_space = bounds_to_doc.inverse().transform_point2(point.document_point);
|
||||
let normalized = (bounds_space - self.bounds[0]) / (self.bounds[1] - self.bounds[0]);
|
||||
|
|
@ -135,16 +144,16 @@ impl SelectedEdges {
|
|||
origin: point.document_point,
|
||||
direction: (point.document_point - bounds_to_doc.transform_point2(pivot)).normalize_or_zero(),
|
||||
};
|
||||
manager.constrained_snap(&snap_data, point, constraint, None)
|
||||
manager.constrained_snap(&snap_data, point, constraint, config)
|
||||
} else if !(self.top || self.bottom) || !(self.left || self.right) {
|
||||
let axis = if !(self.top || self.bottom) { DVec2::X } else { DVec2::Y };
|
||||
let constraint = SnapConstraint::Line {
|
||||
origin: point.document_point,
|
||||
direction: bounds_to_doc.transform_vector2(axis),
|
||||
};
|
||||
manager.constrained_snap(&snap_data, point, constraint, None)
|
||||
manager.constrained_snap(&snap_data, point, constraint, config)
|
||||
} else {
|
||||
manager.free_snap(&snap_data, point, None, false)
|
||||
manager.free_snap(&snap_data, point, config)
|
||||
};
|
||||
point.document_point = old_position;
|
||||
|
||||
|
|
@ -218,7 +227,7 @@ pub fn axis_align_drag(axis_align: bool, position: DVec2, start: DVec2) -> DVec2
|
|||
}
|
||||
|
||||
/// Snaps a dragging event from the artboard or select tool
|
||||
pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &Vec<SnapCandidatePoint>) -> DVec2 {
|
||||
pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 {
|
||||
let mouse_position = axis_align_drag(axis_align, snap_data.input.mouse.position, start);
|
||||
let document = snap_data.document;
|
||||
let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
||||
|
|
@ -228,22 +237,25 @@ pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: Snap
|
|||
|
||||
let bbox = Rect::point_iter(candidates.iter().map(|candidate| candidate.document_point + total_mouse_delta_document));
|
||||
|
||||
for point in candidates {
|
||||
for (index, point) in candidates.iter().enumerate() {
|
||||
let config = SnapTypeConfiguration {
|
||||
bbox,
|
||||
accept_distribution: true,
|
||||
use_existing_candidates: index != 0,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut point = point.clone();
|
||||
point.document_point += total_mouse_delta_document;
|
||||
|
||||
let snapped = if axis_align {
|
||||
snap_manager.constrained_snap(
|
||||
&snap_data,
|
||||
&point,
|
||||
SnapConstraint::Line {
|
||||
origin: point.document_point,
|
||||
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
|
||||
},
|
||||
bbox,
|
||||
)
|
||||
let constraint = SnapConstraint::Line {
|
||||
origin: point.document_point,
|
||||
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
|
||||
};
|
||||
snap_manager.constrained_snap(&snap_data, &point, constraint, config)
|
||||
} else {
|
||||
snap_manager.free_snap(&snap_data, &point, bbox, false)
|
||||
snap_manager.free_snap(&snap_data, &point, config)
|
||||
};
|
||||
|
||||
if best_snap.other_snap_better(&snapped) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::messages::tool::common_functionality::snapping;
|
|||
use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapData;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
|
||||
use graph_craft::document::NodeId;
|
||||
|
|
@ -260,7 +261,7 @@ impl Fsm for ArtboardToolFsmState {
|
|||
|
||||
let point = SnapCandidatePoint::handle(to_document.transform_point2(input.mouse.position));
|
||||
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
|
||||
tool_data.drag_start = snapped.snapped_point_document;
|
||||
tool_data.drag_current = snapped.snapped_point_document;
|
||||
|
|
@ -330,7 +331,8 @@ impl Fsm for ArtboardToolFsmState {
|
|||
|
||||
let document_mouse = to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
|
||||
let snapped = tool_data.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), None, false);
|
||||
let config = SnapTypeConfiguration::default();
|
||||
let snapped = tool_data.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config);
|
||||
let snapped_mouse_position = to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
|
||||
tool_data.snap_manager.update_indicator(snapped);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
|||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
|
||||
|
||||
use graph_craft::document::{value::TaggedValue, NodeId, NodeInput};
|
||||
use graphene_core::Color;
|
||||
|
|
@ -173,7 +173,7 @@ impl Fsm for LineToolFsmState {
|
|||
}
|
||||
(LineToolFsmState::Ready, LineToolMessage::DragStart) => {
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
tool_data.drag_start = snapped.snapped_point_document;
|
||||
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
|
@ -314,6 +314,7 @@ fn generate_transform(tool_data: &mut LineToolData, snap_data: SnapData, lock_an
|
|||
|
||||
let near_point = SnapCandidatePoint::handle_neighbors(document_points[1], [tool_data.drag_start]);
|
||||
let far_point = SnapCandidatePoint::handle_neighbors(2. * document_points[0] - document_points[1], [tool_data.drag_start]);
|
||||
let config = SnapTypeConfiguration::default();
|
||||
|
||||
if constrained {
|
||||
let constraint = SnapConstraint::Line {
|
||||
|
|
@ -321,26 +322,26 @@ fn generate_transform(tool_data: &mut LineToolData, snap_data: SnapData, lock_an
|
|||
direction: document_points[1] - document_points[0],
|
||||
};
|
||||
if center {
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, None);
|
||||
let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, None);
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config);
|
||||
let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, config);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
document_points[1] = document_points[0] * 2. - best.snapped_point_document;
|
||||
document_points[0] = best.snapped_point_document;
|
||||
snap.update_indicator(best);
|
||||
} else {
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, None);
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config);
|
||||
document_points[1] = snapped.snapped_point_document;
|
||||
snap.update_indicator(snapped);
|
||||
}
|
||||
} else if center {
|
||||
let snapped = snap.free_snap(&snap_data, &near_point, None, false);
|
||||
let snapped_far = snap.free_snap(&snap_data, &far_point, None, false);
|
||||
let snapped = snap.free_snap(&snap_data, &near_point, config);
|
||||
let snapped_far = snap.free_snap(&snap_data, &far_point, config);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
document_points[1] = document_points[0] * 2. - best.snapped_point_document;
|
||||
document_points[0] = best.snapped_point_document;
|
||||
snap.update_indicator(best);
|
||||
} else {
|
||||
let snapped = snap.free_snap(&snap_data, &near_point, None, false);
|
||||
let snapped = snap.free_snap(&snap_data, &near_point, config);
|
||||
document_points[1] = snapped.snapped_point_document;
|
||||
snap.update_indicator(snapped);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Inpu
|
|||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
|
||||
use crate::messages::tool::common_functionality::utility_functions::should_extend;
|
||||
|
||||
use bezier_rs::{Bezier, BezierHandles};
|
||||
|
|
@ -395,6 +395,7 @@ impl PenToolData {
|
|||
|
||||
let neighbors = relative.filter(|_| neighbor).map_or(Vec::new(), |neighbor| vec![neighbor]);
|
||||
|
||||
let config = SnapTypeConfiguration::default();
|
||||
if let Some(relative) = relative
|
||||
.map(|layer| transform.transform_point2(layer))
|
||||
.filter(|&relative| (snap_angle || lock_angle) && (relative - document_pos).length_squared() > f64::EPSILON * 100.)
|
||||
|
|
@ -417,8 +418,8 @@ impl PenToolData {
|
|||
let near_point = SnapCandidatePoint::handle_neighbors(document_pos, neighbors.clone());
|
||||
let far_point = SnapCandidatePoint::handle_neighbors(2. * relative - document_pos, neighbors);
|
||||
if colinear {
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, None);
|
||||
let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, None);
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config);
|
||||
let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, config);
|
||||
document_pos = if snapped_far.other_snap_better(&snapped) {
|
||||
snapped.snapped_point_document
|
||||
} else {
|
||||
|
|
@ -426,13 +427,13 @@ impl PenToolData {
|
|||
};
|
||||
snap.update_indicator(if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far });
|
||||
} else {
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, None);
|
||||
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config);
|
||||
document_pos = snapped.snapped_point_document;
|
||||
snap.update_indicator(snapped);
|
||||
}
|
||||
} else if let Some(relative) = relative.map(|layer| transform.transform_point2(layer)).filter(|_| colinear) {
|
||||
let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors.clone()), None, false);
|
||||
let snapped_far = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(2. * relative - document_pos, neighbors), None, false);
|
||||
let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors.clone()), config);
|
||||
let snapped_far = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(2. * relative - document_pos, neighbors), config);
|
||||
document_pos = if snapped_far.other_snap_better(&snapped) {
|
||||
snapped.snapped_point_document
|
||||
} else {
|
||||
|
|
@ -440,7 +441,7 @@ impl PenToolData {
|
|||
};
|
||||
snap.update_indicator(if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far });
|
||||
} else {
|
||||
let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors), None, false);
|
||||
let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors), config);
|
||||
document_pos = snapped.snapped_point_document;
|
||||
snap.update_indicator(snapped);
|
||||
}
|
||||
|
|
@ -456,7 +457,7 @@ impl PenToolData {
|
|||
|
||||
fn create_initial_point(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, tool_options: &PenOptions, append: bool) {
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
|
||||
let selected_nodes = document.network_interface.selected_nodes(&[]).unwrap();
|
||||
|
|
@ -632,7 +633,7 @@ impl Fsm for PenToolFsmState {
|
|||
}
|
||||
(PenToolFsmState::PlacingAnchor, PenToolMessage::DragStart { append_to_selected }) => {
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
// Early return if the buffer was started and this message is being run again after the buffer (so that place_anchor updates the state with the newly merged vector)
|
||||
if tool_data.buffering_merged_vector {
|
||||
|
|
|
|||
Loading…
Reference in New Issue