Repository: godotengine/godot (language: cpp)

Issue:
`Node2D.rotation == NAN` causes issues with 2D editor
### Tested versions

- Reproducible in v4.3.stable

### System information

Windows 7, Godot v4.3.stable

### Issue description

When `Node2D.rotation == NAN` in editor, the node will not be displayed anywhere, and if you will select this node and press "Center view button", 2D editor will start working wrong. It won't display any of UI elements(like origin, viewport) and rulers will have no numbers on them(like on image below).
![NanRotationBug](https://github.com/user-attachments/assets/d79958a1-14b8-48b4-bbe7-5692e7404e61)


### Steps to reproduce

1. In the scene tree dock, select the node2d(or any other 2d node) with `rotation == NAN`.
2. Press **"Center view"** button.

### Minimal reproduction project (MRP)

MRP includes Readme.txt to help you to reproduce the bug.
[github-nan-rotation-reproduction-project.zip](https://github.com/user-attachments/files/16954949/github-nan-rotation-reproduction-project.zip)


Discussion / hints:
Similar issue in 3D.

I'd say the item not being displayed is correct, but trying to center view on it should rather do nothing instead of propagating NANs into canvas/ruler/etc. calculations.

Fix patch:
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 7381f2ab83a1..169c4b1c5d97 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4882,31 +4882,30 @@ void CanvasItemEditor::_focus_selection(int p_op) {
 		if (!ci) {
 			continue;
 		}
-
-		// counting invisible items, for now
-		//if (!ci->is_visible_in_tree()) continue;
-		++count;
-
+		const Transform2D canvas_item_transform = ci->get_global_transform();
+		if (!canvas_item_transform.is_finite()) {
+			continue;
+		}
 		Rect2 item_rect;
 		if (ci->_edit_use_rect()) {
 			item_rect = ci->_edit_get_rect();
 		} else {
 			item_rect = Rect2();
 		}
-
-		Vector2 pos = ci->get_global_transform().get_origin();
-		Vector2 scale = ci->get_global_transform().get_scale();
-		real_t angle = ci->get_global_transform().get_rotation();
+		Vector2 pos = canvas_item_transform.get_origin();
+		const Vector2 scale = canvas_item_transform.get_scale();
+		const real_t angle = canvas_item_transform.get_rotation();
 		pos = ci->get_viewport()->get_popup_base_transform().xform(pos);
 
 		Transform2D t(angle, Vector2(0.f, 0.f));
 		item_rect = t.xform(item_rect);
 		Rect2 canvas_item_rect(pos + scale * item_rect.position, scale * item_rect.size);
-		if (count == 1) {
+		if (count == 0) {
 			rect = canvas_item_rect;
 		} else {
 			rect = rect.merge(canvas_item_rect);
 		}
+		count++;
 	}
 
 	if (p_op == VIEW_FRAME_TO_SELECTION && rect.size.x > CMP_EPSILON && rect.size.y > CMP_EPSILON) {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 058adbdb1977..50c0d52abe3b 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2997,6 +2997,9 @@ void Node3DEditorViewport::_notification(int p_what) {
 				}
 
 				Transform3D t = sp->get_global_gizmo_transform();
+				if (!t.is_finite()) {
+					continue;
+				}
 				AABB new_aabb = _calculate_spatial_bounds(sp);
 
 				exist = true;
@@ -4345,29 +4348,34 @@ void Node3DEditorViewport::focus_selection() {
 
 	const List<Node *> &selection = editor_selection->get_selected_node_list();
 
-	for (Node *E : selection) {
-		Node3D *sp = Object::cast_to<Node3D>(E);
-		if (!sp) {
+	for (Node *node : selection) {
+		Node3D *node_3d = Object::cast_to<Node3D>(node);
+		if (!node_3d) {
 			continue;
 		}
 
-		Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+		Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(node_3d);
 		if (!se) {
 			continue;
 		}
 
 		if (se->gizmo.is_valid()) {
 			for (const KeyValue<int, Transform3D> &GE : se->subgizmos) {
-				center += se->gizmo->get_subgizmo_transform(GE.key).origin;
-				count++;
+				const Vector3 pos = se->gizmo->get_subgizmo_transform(GE.key).origin;
+				if (pos.is_finite()) {
+					center += pos;
+					count++;
+				}
 			}
 		}
-
-		center += sp->get_global_gizmo_transform().origin;
-		count++;
+		const Vector3 pos = node_3d->get_global_gizmo_transform().origin;
+		if (pos.is_finite()) {
+			center += pos;
+			count++;
+		}
 	}
 
-	if (count != 0) {
+	if (count > 1) {
 		center /= count;
 	}
 
@@ -4477,21 +4485,24 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos, Node3D
 }
 
 AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_omit_top_level, const Transform3D *p_bounds_orientation) {
+	if (!p_parent) {
+		return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
+	}
+	const Transform3D parent_transform = p_parent->get_global_transform();
+	if (!parent_transform.is_finite()) {
+		return AABB();
+	}
 	AABB bounds;
 
 	Transform3D bounds_orientation;
+	Transform3D xform_to_top_level_parent_space;
 	if (p_bounds_orientation) {
 		bounds_orientation = *p_bounds_orientation;
+		xform_to_top_level_parent_space = bounds_orientation.affine_inverse() * parent_transform;
 	} else {
-		bounds_orientation = p_parent->get_global_transform();
-	}
-
-	if (!p_parent) {
-		return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
+		bounds_orientation = parent_transform;
 	}
 
-	const Transform3D xform_to_top_level_parent_space = bounds_orientation.affine_inverse() * p_parent->get_global_transform();
-
 	const VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(p_parent);
 	if (visual_instance) {
 		bounds = visual_instance->get_aabb();
@@ -6241,6 +6252,9 @@ void Node3DEditor::update_transform_gizmo() {
 	if (se && se->gizmo.is_valid()) {
 		for (const KeyValue<int, Transform3D> &E : se->subgizmos) {
 			Transform3D xf = se->sp->get_global_transform() * se->gizmo->get_subgizmo_transform(E.key);
+			if (!xf.is_finite()) {
+				continue;
+			}
 			gizmo_center += xf.origin;
 			if (count == 0 && local_gizmo_coords) {
 				gizmo_basis = xf.basis;
@@ -6265,6 +6279,9 @@ void Node3DEditor::update_transform_gizmo() {
 			}
 
 			Transform3D xf = sel_item->sp->get_global_transform();
+			if (!xf.is_finite()) {
+				continue;
+			}
 			gizmo_center += xf.origin;
 			if (count == 0 && local_gizmo_coords) {
 				gizmo_basis = xf.basis;


Test patch: