From 4e64c7a1892f2275b6c7b8db2a0b5cd03fcdbf3a Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 10 Jan 2025 15:37:38 +0530 Subject: [PATCH 1/4] Fix snapping to respect rotation of bounding box Fixes snapping behaviour which defaulted to X and Y axes. --- .../common_functionality/snapping/alignment_snapper.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs index 76cbb66e7f..1c589a99ea 100644 --- a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs +++ b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs @@ -74,7 +74,14 @@ impl AlignmentSnapper { Quad::intersect_rays(target_point.document_point, DVec2::X, origin, direction), ] } else { - [DVec2::new(point.document_point.x, target_position.y), DVec2::new(target_position.x, point.document_point.y)].map(Some) + let Some(quad) = target_point.quad else { + continue; + }; + let quad = quad.0; + let edges = [quad[1] - quad[0], quad[3] - quad[0]]; + edges + .map(|edge| edge.try_normalize().map(|edge| (point.document_point - target_position).project_onto(edge) + target_position)) + .into() }; let target_path = matches!(target_point.target, SnapTarget::Path(_)); From 828835612bf812a8159773564cde11cd38294c43 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 11 Jan 2025 10:02:09 +0530 Subject: [PATCH 2/4] Remove redundant align along edges --- .../portfolio/document/utility_types/misc.rs | 26 +++++-------------- .../tool/common_functionality/snapping.rs | 9 +------ .../snapping/alignment_snapper.rs | 2 +- .../snapping/layer_snapper.rs | 3 --- 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/misc.rs b/editor/src/messages/portfolio/document/utility_types/misc.rs index b3c99e594f..3cd514554b 100644 --- a/editor/src/messages/portfolio/document/utility_types/misc.rs +++ b/editor/src/messages/portfolio/document/utility_types/misc.rs @@ -91,7 +91,6 @@ impl SnappingState { match target { SnapTarget::BoundingBox(target) => match target { BoundingBoxSnapTarget::CornerPoint => self.bounding_box.corner_point, - BoundingBoxSnapTarget::AlongEdge => self.bounding_box.along_edge, BoundingBoxSnapTarget::EdgeMidpoint => self.bounding_box.edge_midpoint, BoundingBoxSnapTarget::CenterPoint => self.bounding_box.center_point, }, @@ -106,7 +105,7 @@ impl SnappingState { SnapTarget::Artboard(_) => self.artboards, SnapTarget::Grid(_) => self.grid_snapping, SnapTarget::Alignment(AlignmentSnapTarget::AlignWithAnchorPoint) => self.path.align_with_anchor_point, - SnapTarget::Alignment(_) => self.bounding_box.align_with_corner_point, + SnapTarget::Alignment(_) => self.bounding_box.align_with_edges, SnapTarget::DistributeEvenly(_) => self.bounding_box.distribute_evenly, _ => false, } @@ -119,8 +118,7 @@ pub struct BoundingBoxSnapping { pub center_point: bool, pub corner_point: bool, pub edge_midpoint: bool, - pub along_edge: bool, - pub align_with_corner_point: bool, + pub align_with_edges: bool, pub distribute_evenly: bool, } @@ -130,8 +128,7 @@ impl Default for BoundingBoxSnapping { center_point: true, corner_point: true, edge_midpoint: true, - along_edge: true, - align_with_corner_point: true, + align_with_edges: true, distribute_evenly: true, } } @@ -378,13 +375,11 @@ impl fmt::Display for SnapSource { } type GetSnapState = for<'a> fn(&'a mut SnappingState) -> &'a mut bool; -pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 6] = [ +pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 5] = [ ( - // TODO: Rename to "Beyond Edges" and update behavior to snap to an infinite extension of the bounding box edges - // TODO: (even when the layer is locally rotated) instead of horizontally/vertically aligning with the corner points - "Align with Corner Points", - (|snapping_state| &mut snapping_state.bounding_box.align_with_corner_point) as GetSnapState, - "Snaps to horizontal/vertical alignment with the corner points of any layer's bounding box", + "Align with Edges", + (|snapping_state| &mut snapping_state.bounding_box.align_with_edges) as GetSnapState, + "Snaps to horizontal/vertical alignment with the edges of any layer's bounding box" ), ( "Corner Points", @@ -401,11 +396,6 @@ pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 6] = [ (|snapping_state| &mut snapping_state.bounding_box.edge_midpoint) as GetSnapState, "Snaps to any of the four points at the middle of the edges of any layer's bounding box", ), - ( - "Along Edges", - (|snapping_state| &mut snapping_state.bounding_box.along_edge) as GetSnapState, - "Snaps anywhere along the four edges of any layer's bounding box", - ), ( "Distribute Evenly", (|snapping_state| &mut snapping_state.bounding_box.distribute_evenly) as GetSnapState, @@ -463,7 +453,6 @@ pub enum BoundingBoxSnapTarget { CornerPoint, CenterPoint, EdgeMidpoint, - AlongEdge, } impl fmt::Display for BoundingBoxSnapTarget { @@ -472,7 +461,6 @@ impl fmt::Display for BoundingBoxSnapTarget { BoundingBoxSnapTarget::CornerPoint => write!(f, "Bounding Box: Corner Point"), BoundingBoxSnapTarget::CenterPoint => write!(f, "Bounding Box: Center Point"), BoundingBoxSnapTarget::EdgeMidpoint => write!(f, "Bounding Box: Edge Midpoint"), - BoundingBoxSnapTarget::AlongEdge => write!(f, "Bounding Box: Along Edge"), } } } diff --git a/editor/src/messages/tool/common_functionality/snapping.rs b/editor/src/messages/tool/common_functionality/snapping.rs index a289ee7fde..d23b2c54c0 100644 --- a/editor/src/messages/tool/common_functionality/snapping.rs +++ b/editor/src/messages/tool/common_functionality/snapping.rs @@ -8,7 +8,7 @@ pub use {alignment_snapper::*, distribution_snapper::*, grid_snapper::*, layer_s use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_SNAP_BACKGROUND, COLOR_OVERLAY_WHITE}; use crate::messages::portfolio::document::overlays::utility_types::{OverlayContext, Pivot}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; -use crate::messages::portfolio::document::utility_types::misc::{BoundingBoxSnapTarget, GridSnapTarget, PathSnapTarget, SnapTarget}; +use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, PathSnapTarget, SnapTarget}; use crate::messages::prelude::*; use bezier_rs::{Subpath, TValue}; @@ -135,14 +135,7 @@ fn get_closest_line(lines: &[SnappedLine]) -> Option<&SnappedPoint> { fn get_closest_intersection(snap_to: DVec2, curves: &[SnappedCurve]) -> Option { let mut best = None; for curve_i in curves { - if curve_i.point.target == SnapTarget::BoundingBox(BoundingBoxSnapTarget::AlongEdge) { - continue; - } - for curve_j in curves { - if curve_j.point.target == SnapTarget::BoundingBox(BoundingBoxSnapTarget::AlongEdge) { - continue; - } if curve_i.start == curve_j.start && curve_i.layer == curve_j.layer { continue; } diff --git a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs index 1c589a99ea..2d4606cb19 100644 --- a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs +++ b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs @@ -19,7 +19,7 @@ impl AlignmentSnapper { let document = snap_data.document; self.bounding_box_points.clear(); - if !document.snapping_state.bounding_box.align_with_corner_point { + if !document.snapping_state.bounding_box.align_with_edges { return; } diff --git a/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs index fb1d6767fc..a630ecd202 100644 --- a/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs +++ b/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs @@ -86,9 +86,6 @@ impl LayerSnapper { } } } - if !snap_data.ignore_bounds(layer) { - self.add_layer_bounds(document, layer, SnapTarget::BoundingBox(BoundingBoxSnapTarget::AlongEdge)); - } } } From e851aa48a98db6505f4d549f04a4873cc4693a2d Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 13 Jan 2025 02:32:17 -0800 Subject: [PATCH 3/4] Code review --- .../messages/portfolio/document/utility_types/misc.rs | 2 +- .../common_functionality/snapping/alignment_snapper.rs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/misc.rs b/editor/src/messages/portfolio/document/utility_types/misc.rs index 3cd514554b..6db72e8e56 100644 --- a/editor/src/messages/portfolio/document/utility_types/misc.rs +++ b/editor/src/messages/portfolio/document/utility_types/misc.rs @@ -379,7 +379,7 @@ pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 5] = [ ( "Align with Edges", (|snapping_state| &mut snapping_state.bounding_box.align_with_edges) as GetSnapState, - "Snaps to horizontal/vertical alignment with the edges of any layer's bounding box" + "Snaps to horizontal/vertical alignment with the edges of any layer's bounding box", ), ( "Corner Points", diff --git a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs index 2d4606cb19..b99b1ecc28 100644 --- a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs +++ b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs @@ -74,14 +74,9 @@ impl AlignmentSnapper { Quad::intersect_rays(target_point.document_point, DVec2::X, origin, direction), ] } else { - let Some(quad) = target_point.quad else { - continue; - }; - let quad = quad.0; + let Some(quad) = target_point.quad.map(|quad| quad.0) else { continue }; let edges = [quad[1] - quad[0], quad[3] - quad[0]]; - edges - .map(|edge| edge.try_normalize().map(|edge| (point.document_point - target_position).project_onto(edge) + target_position)) - .into() + edges.map(|edge| edge.try_normalize().map(|edge| (point.document_point - target_position).project_onto(edge) + target_position)) }; let target_path = matches!(target_point.target, SnapTarget::Path(_)); From d03cd755810f9438dd3f6cb8c78dffa8762a9dcd Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 13 Jan 2025 02:45:09 -0800 Subject: [PATCH 4/4] Update manual --- website/content/learn/interface/document-panel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/learn/interface/document-panel.md b/website/content/learn/interface/document-panel.md index 1ec71cc56d..ea8bbee5a0 100644 --- a/website/content/learn/interface/document-panel.md +++ b/website/content/learn/interface/document-panel.md @@ -55,7 +55,7 @@ The right side of the control bar has controls related to the active document an | | | |-|-| | Overlays |

When checked (default), overlays are shown. When unchecked, they are hidden. Overlays are the temporary contextual visualizations (like bounding boxes and vector manipulators) that are usually blue and appear atop the viewport when using tools.

| -| Snapping |

When checked (default), drawing and dragging shapes and vector points means they will snap to other areas of geometric interest like corners or anchor points. When unchecked, the selection moves freely.

Fine-grained options are available by clicking the overflow button to access its options popover menu:

Snapping options popover menu

Snapping options relating to **Bounding Boxes**:

  • **Align with Corner Points**: Snaps to horizontal/vertical alignment with the corner points of any layer's bounding box.
  • **Corner Points**: Snaps to the four corners of any layer's bounding box.
  • **Center Points**: Snaps to the center point of any layer's bounding box.
  • **Edge Midpoints**: Snaps to any of the four points at the middle of the edges of any layer's bounding box.
  • **Along Edges**: Snaps anywhere along the four edges of any layer's bounding box.
  • **Distribute Evenly**: Snaps to a consistent distance offset established by the bounding boxes of nearby layers (due to a bug, **Center Points** and **Corner Points** must be enabled).

Snapping options relating to **Paths**:

  • **Align with Anchor Points**: Snaps to horizontal/vertical alignment with the anchor points of any vector path.
  • **Anchor Points**: Snaps to the anchor point of any vector path.
  • **Line Midpoints**: Snaps to the point at the middle of any straight line segment of a vector path.
  • **Path Intersection Points**: Snaps to any points where vector paths intersect.
  • **Along Paths**: Snaps along the length of any vector path.
  • **Normal to Paths**: Snaps a line to a point perpendicular to a vector path (due to a bug, **Intersections of Paths** must be enabled).
  • **Tangent to Paths**: Snaps a line to a point tangent to a vector path (due to a bug, **Intersections of Paths** must be enabled).

| +| Snapping |

When checked (default), drawing and dragging shapes and vector points means they will snap to other areas of geometric interest like corners or anchor points. When unchecked, the selection moves freely.

Fine-grained options are available by clicking the overflow button to access its options popover menu. Each option has a tooltip explaining what it does by hovering the cursor over it.

Snapping options popover menu

Snapping options relating to **Bounding Boxes**:

  • **Align with Edges**: Snaps to horizontal/vertical alignment with the edges of any layer's bounding box.
  • **Corner Points**: Snaps to the four corners of any layer's bounding box.
  • **Center Points**: Snaps to the center point of any layer's bounding box.
  • **Edge Midpoints**: Snaps to any of the four points at the middle of the edges of any layer's bounding box.
  • **Distribute Evenly**: Snaps to a consistent distance offset established by the bounding boxes of nearby layers (due to a bug, **Corner Points** and **Center Points** must be enabled).

Snapping options relating to **Paths**:

  • **Align with Anchor Points**: Snaps to horizontal/vertical alignment with the anchor points of any vector path.
  • **Anchor Points**: Snaps to the anchor point of any vector path.
  • **Line Midpoints**: Snaps to the point at the middle of any straight line segment of a vector path.
  • **Path Intersection Points**: Snaps to any points where vector paths intersect.
  • **Along Paths**: Snaps along the length of any vector path.
  • **Normal to Paths**: Snaps a line to a point perpendicular to a vector path (due to a bug, **Intersections of Paths** must be enabled).
  • **Tangent to Paths**: Snaps a line to a point tangent to a vector path (due to a bug, **Intersections of Paths** must be enabled).

| | Grid |

When checked (off by default), grid lines are shown and snapping to them becomes active. The initial grid scale is 1 document unit, helping you draw pixel-perfect artwork.

  • **Type** sets whether the grid pattern is made of squares or triangles.

    **Rectangular** is a pattern of horizontal and vertical lines:

    Snapping options popover menu

    It has one option unique to this mode:

    • **Spacing** is the width and height of the rectangle grid cells.

    **Isometric** is a pattern of triangles:

    Snapping options popover menu

    It has two options unique to this mode:

    • **Y Spacing** is the height between vertical repetitions of the grid.
    • **Angles** is the slant of the upward and downward sloped grid lines.
  • **Display** gives control over the appearance of the grid. The **Display as dotted grid** checkbox (off by default) replaces the solid lines with dots at their intersection points.
  • **Origin** is the position in the canvas where the repeating grid pattern begins from. If you need an offset for the grid where an intersection occurs at a specific location, set those coordinates.
| | View Mode |

**Normal** (default): The artwork is rendered normally.

**Outline**: The artwork is rendered as a wireframe.

**Pixels**: **Not implemented yet.** The artwork is rendered as it would appear when exported as a bitmap image at 100% scale regardless of the viewport zoom level.

| | Zoom In |

Zooms the viewport in to the next whole increment.

|