diff --git a/jung-algorithms/src/main/java/edu/uci/ics/jung/layout/algorithms/FRLayoutAlgorithm.java b/jung-algorithms/src/main/java/edu/uci/ics/jung/layout/algorithms/FRLayoutAlgorithm.java index ceb09e4d1..048b5c62c 100644 --- a/jung-algorithms/src/main/java/edu/uci/ics/jung/layout/algorithms/FRLayoutAlgorithm.java +++ b/jung-algorithms/src/main/java/edu/uci/ics/jung/layout/algorithms/FRLayoutAlgorithm.java @@ -189,10 +189,11 @@ protected synchronized void calcPositions(N node) { positionX = layoutModel.getWidth() - borderWidth - random.nextDouble() * borderWidth * 2.0; } - if (positionY < borderWidth) { - positionY = borderWidth + random.nextDouble() * borderWidth * 2.0; - } else if (positionY > layoutModel.getWidth() - borderWidth * 2) { - positionY = layoutModel.getWidth() - borderWidth - random.nextDouble() * borderWidth * 2.0; + double borderHeight = layoutModel.getHeight() / 50.0; + if (positionY < borderHeight) { + positionY = borderHeight + random.nextDouble() * borderHeight * 2.0; + } else if (positionY > layoutModel.getHeight() - borderHeight * 2) { + positionY = layoutModel.getHeight() - borderHeight - random.nextDouble() * borderHeight * 2.0; } layoutModel.set(node, positionX, positionY); diff --git a/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutLocationsTest.java b/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutLocationsTest.java new file mode 100644 index 000000000..e35a15de3 --- /dev/null +++ b/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutLocationsTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, the JUNG Project and the Regents of the University + * of California. All rights reserved. + * + * This software is open-source under the BSD license; see + * https://github.com/jrtom/jung/blob/master/LICENSE for a description. + */ +package edu.uci.ics.jung.layout.spatial; + +import com.google.common.graph.GraphBuilder; +import com.google.common.graph.MutableGraph; +import edu.uci.ics.jung.layout.algorithms.FRLayoutAlgorithm; +import edu.uci.ics.jung.layout.model.LayoutModel; +import edu.uci.ics.jung.layout.model.LoadingCacheLayoutModel; +import edu.uci.ics.jung.layout.model.Point; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests the fix for incorrect Y-coordinate distribution in FRLayoutAlgorithm. Previously, nodes + * were arranged in a square (width × width), ignoring the configured layout height. + * + *

To verify the fix: 1. Generate enough nodes to exceed the layout bounds. 2. Ensure all nodes + * are positioned within the specified width * height area after layout. + * + * @author melanxoluk + */ +public class FRLayoutLocationsTest { + private static final int layoutWidth = 2000; + private static final int layoutHeight = 500; + private static final int iterations = 200; + private static final int nodes = 20; + + @Test + public void testTargetCoordinates() { + MutableGraph graph = GraphBuilder.directed().build(); + LoadingCacheLayoutModel.Builder builder = + LoadingCacheLayoutModel.builder() + .setGraph(graph) + .setSize(layoutWidth, layoutHeight); + + LayoutModel layoutModel = new FRLayoutsTest.TestLayoutModel<>(builder, iterations); + + for (int i = 0; i < nodes; i++) { + graph.addNode(i); + layoutModel.set(i, Point.of(i, i)); + } + + FRLayoutAlgorithm algorithm = new FRLayoutAlgorithm(); + layoutModel.accept(algorithm); + + Assert.assertTrue( + "All points should has coordinates into target layout size", + layoutModel.getLocations().values().stream() + .allMatch(it -> it.y <= layoutHeight && it.x <= layoutWidth)); + } +} diff --git a/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutsTest.java b/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutsTest.java index 4d72d9677..7ab043a63 100644 --- a/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutsTest.java +++ b/jung-algorithms/src/test/java/edu/uci/ics/jung/layout/spatial/FRLayoutsTest.java @@ -142,7 +142,7 @@ private static boolean closeEnough(Map left, Map r * * @param */ - private static class TestLayoutModel extends LoadingCacheLayoutModel { + public static class TestLayoutModel extends LoadingCacheLayoutModel { // how many steps private int steps;