On Sun, 30 Nov 2025 03:25:20 GMT, Michael Strauß <[email protected]> wrote:
> When a `Scene` or `SubScene` has its width or height set to 0, coordinate
> transformations stop working because the transformation matrix contains NaNs.
> This is a consequence of divisions by zero in both parallel and perspective
> projections.
>
> Even though a 0x0 scene is mathematically degenerate, it is still desirable
> for coordinate transformation APIs to remain numerically well-behaved and
> return finite results whenever possible, rather than being poisoned by
> NaN/Infinity.
>
> Here is an application that demonstrates the failing coordinate
> transformations. Click on the buttons to resize the SubScene and observe the
> console output. After applying the patch in this PR, you should observe that
> `localToScreen()` no longer returns NaN.
>
>
> public class ZeroSizeSubScene extends Application {
>
> @Override
> public void start(Stage stage) {
> var rect = new Rectangle(50, 50, Color.RED);
> var subScene = new SubScene(new Group(rect), 100, 100);
> subScene.setFill(Color.GRAY);
>
> // Also try a perspective camera:
> //
> // var camera = new PerspectiveCamera();
> // camera.setRotate(45);
> // camera.setTranslateX(-20);
> // camera.setRotationAxis(new Point3D(0, 1, 0));
> // subScene.setCamera(camera);
>
> class MyButton extends Button {
> public MyButton(String text, double width, double height) {
> super(text);
> setOnAction(_ -> {
> var timeline = new Timeline(
> new KeyFrame(Duration.seconds(1), new
> KeyValue(subScene.widthProperty(), width)),
> new KeyFrame(Duration.seconds(1), new
> KeyValue(subScene.heightProperty(), height)));
>
> timeline.setOnFinished(_ -> {
> Point2D p0 = rect.localToScreen(0, 0);
> System.out.println("rect.localToScreen(0, 0) = " +
> p0);
> });
>
> timeline.play();
> });
> }
> }
>
> VBox.setMargin(subScene, new Insets(0, 0, 20, 0));
>
> var root = new VBox(5,
> subScene,
> new CheckBox("Rotate SubScene") {{ setOnAction(_ ->
> subScene.setRotate(isSelected() ? 45 : 0)); }},
> new MyButton("Size: 100x100", 100, 100),
> new MyButton("Size: 10x10", 10, 10),
> new MyButton("Size: 100x0", 100, 0),
> new MyButton("Size: 0x100", 0, 100),
> new MyButton("Size: 0x0", 0, 0)
> );
>
> S...
Looks good on macOS.
modules/javafx.graphics/src/main/java/javafx/scene/Camera.java line 339:
> 337: // and height to ulp(1), guaranteeing non-zero view dimensions
> while keeping the clamp very small.
> 338: //
> 339: this.viewWidth = Math.max(Math.ulp(1.0), width);
minor suggestion: create a private static function (`safeSize` ?) with the
comment explaining why.
-------------
Marked as reviewed by angorya (Reviewer).
PR Review: https://git.openjdk.org/jfx/pull/1992#pullrequestreview-3527148686
PR Review Comment: https://git.openjdk.org/jfx/pull/1992#discussion_r2578790529