Skip to content

Fix #4619: Fallback to identity transform for zero-width layers in tr… - #4624

Open
shubhtrek wants to merge 3 commits into
GraphiteEditor:masterfrom
shubhtrek:fix-zero-width-transform-cage
Open

shubhtrek wants to merge 3 commits into
GraphiteEditor:masterfrom
shubhtrek:fix-zero-width-transform-cage

Conversation

@shubhtrek

@shubhtrek shubhtrek commented Sep 30, 2026 •

Copy link
Copy Markdown

Closes #4619

Summary

When a layer is collapsed to zero width or height, its transform matrix has a determinant of 0 and cannot be inverted. Previously, adding a small 1e-4 epsilon to the diagonal caused the inverted translation terms to blow up, displacing the transform cage away from the layer.

This PR replaces the matrix perturbation with a fallback to DAffine2::IDENTITY, allowing the bounding box to be computed directly in viewport space so the transform cage stays properly aligned over the layer.

Preview

zero_width_transform_cage_proof

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Confidence score: 5/5

  • editor/src/messages/tool/common_functionality/shapes/shape_utility.rs duplicates fallback transform logic from select_tool.rs, which could let the two paths drift and handle transforms inconsistently; consider extracting a shared helper.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="editor/src/messages/tool/common_functionality/shapes/shape_utility.rs">

<violation number="1" location="editor/src/messages/tool/common_functionality/shapes/shape_utility.rs:253">
P3: `transform_cage_overlays` now duplicates verbatim the fallback logic added to `select_tool.rs`: the `find` + singular-det fallback (which re-implements `create_bounding_box_transform`), the `transform_tampered` `.any()` scan, and the `filter_map` bounds computation. Both copies must be kept in sync, and the new fallback semantics make any drift silently change behavior in one tool but not the other. Extract the three pieces into one shared helper (leave `create_bounding_box_transform` where it is, but move it plus a `selection_bounds(...)` helper into a common module) and call it from both `select_tool.rs` and `transform_cage_overlays`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread editor/src/messages/tool/common_functionality/shapes/shape_utility.rs Outdated
Comment thread editor/src/messages/tool/tool_messages/select_tool.rs Outdated
Comment thread editor/src/messages/tool/tool_messages/select_tool.rs Outdated
Comment thread editor/src/messages/tool/tool_messages/select_tool.rs Outdated
.find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
.map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
.map(|layer| {
let transform = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: transform_cage_overlays now duplicates verbatim the fallback logic added to select_tool.rs: the find + singular-det fallback (which re-implements create_bounding_box_transform), the transform_tampered .any() scan, and the filter_map bounds computation. Both copies must be kept in sync, and the new fallback semantics make any drift silently change behavior in one tool but not the other. Extract the three pieces into one shared helper (leave create_bounding_box_transform where it is, but move it plus a selection_bounds(...) helper into a common module) and call it from both select_tool.rs and transform_cage_overlays.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At editor/src/messages/tool/common_functionality/shapes/shape_utility.rs, line 253:

<comment>`transform_cage_overlays` now duplicates verbatim the fallback logic added to `select_tool.rs`: the `find` + singular-det fallback (which re-implements `create_bounding_box_transform`), the `transform_tampered` `.any()` scan, and the `filter_map` bounds computation. Both copies must be kept in sync, and the new fallback semantics make any drift silently change behavior in one tool but not the other. Extract the three pieces into one shared helper (leave `create_bounding_box_transform` where it is, but move it plus a `selection_bounds(...)` helper into a common module) and call it from both `select_tool.rs` and `transform_cage_overlays`.</comment>

<file context>
@@ -244,30 +244,41 @@ pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier,
 		.find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
-		.map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
+		.map(|layer| {
+			let transform = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface);
+			if transform.matrix2.determinant() == 0. {
+				document.metadata().document_to_viewport
</file context>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transform cage incorrect when layer has zero width

1 participant