0

I have the following code which iterates through my models list and than creates nodes in the area

        final AtomicDouble x = new AtomicDouble(0.0);
        final AtomicDouble y = new AtomicDouble(0.0);
        bottomAnchorPane.getChildren().clear();
        modelSet.getModels().stream().forEach(model -> {
            final DraggableNode node = new DraggableNode();
            node.setType(DragIconType.MODEL);
            node.setTitle(model.getName());
            bottomAnchorPane.getChildren().add(node);
            node.relocateToPoint(new Point2D(x.get(), y.get()));
            x.addAndGet(10 + Math.random() * (50 - 10));
            y.addAndGet(20 + Math.random() * (300 - 50));
        });

public class DraggableNode extends AnchorPane {

   public void relocateToPoint(final Point2D p) {
        final Point2D localCoords = getParent().sceneToLocal(p);
        relocate((int) (localCoords.getX() - dragOffset.getX()),
                (int) (localCoords.getY() - dragOffset.getY()));
    }
}

It looks like following now. I want to evenly spread it over the entire area. enter image description here

node.relocateToPoint(new Point2D(x.get(), y.get())); 

is the key here which takes node position x,y but somehow my randomization is not working nice. Is there a better way.

Saurabh Kumar
  • 16,353
  • 49
  • 133
  • 212
  • the values `50` and `300` are the actual dimensions of the AnchroPane? If not, then what are their meaning ? I would expect something like : `x.addAndGet(paddingValue + Math.random() * (paneWidth - paddingValue));` and the same for the height of course. – JKostikiadis Nov 03 '17 at 09:04
  • @JKostikiadis Thank you for the reply. Those are just some random numbers i picked. Could you please tell me what is paddingValue. PaneWidth i assume is parent anchorPane width. Right? – Saurabh Kumar Nov 03 '17 at 09:11
  • Well i saw you are adding +10 from the start and -10 from the end. so I am guessing you want to have a 'padding' or better a 'margin' inside the AnchorPane where you add (relocate) your nodes, in that case that value is the paddingValue i used. (I just used a variable to remove the "Magic Number" effect). Yes the paneWidth should be the actual AnchorPane width if you want to spread the Nodes inside the AnchorPane. Of course you will have to do the same with height like : `y.addAndGet(paddingValue + Math.random() * (paneHeight - paddingValue));` – JKostikiadis Nov 03 '17 at 09:17
  • @JKostikiadis I tried your suggestion but still they are arranged in a snake like structure from top to bottom. Somehow i feel the random techinique is not really random but incremental sequence. Is there any library to achieve that ? – Saurabh Kumar Nov 03 '17 at 09:29
  • I post an example which you might find helpful. Furthermore I would like to see the `addAndGet` method and how you actually update the x and y values of the Nodes inside the AnchorPane. – JKostikiadis Nov 03 '17 at 10:14
  • AnchorPane lays out children based on constraint Saurabh not relative to a point – Elltz Nov 03 '17 at 12:01

1 Answers1

0

Here is an example of how you could relocate your nodes in random locations :

import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class RandomRelocateTest extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        BorderPane box = new BorderPane();

        AnchorPane mainPane = new AnchorPane();

        addPanes(mainPane);

        Button button = new Button("Randomize Location");
        button.setOnAction(e -> {
            randomizeLoc(mainPane);
        });

        box.setCenter(mainPane);
        box.setBottom(button);

        Scene scene = new Scene(box, 550, 450);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // Add 15 rectangle to a specific location
    private void addPanes(AnchorPane mainPane) {
        for (int i = 0; i < 15; i++) {
            Rectangle rec = new Rectangle();
            rec.setStyle("-fx-border-color: black");
            rec.setWidth(20);
            rec.setHeight(20);

            rec.relocate(50 + 20 * i + 5 * i, 10);

            mainPane.getChildren().add(rec);
        }
    }

    private void randomizeLoc(AnchorPane mainPane) {

        double myMargins = 30;
        double rectangleSize = 20;

        double paneWidth = mainPane.getWidth() - myMargins - rectangleSize;
        double paneHeight = mainPane.getHeight() - myMargins - rectangleSize;

        // Get all the Nodes inside the AnchorPane
        ObservableList<Node> childrens = mainPane.getChildren();
        for (Node n : childrens) {

            double x = myMargins + Math.random() * (paneWidth);
            double y = myMargins + Math.random() * (paneHeight);

            n.relocate(x, y);
        }
    }
}

Have a look at the randomizeLoc() and I am going to add some pictures explaining the logic of my calculations.

enter image description here

Edit : Above there is an example of a AnchorPane. The actual dimensions is the filled rectangle and the area we want to draw the Object is the Dotted Rectangle. Now the Math.random will give you a number between 0.0 and 1.0. First of all we want to be sure that we are inside the Dotted Area so the upper left corner is at (20,20) ( if we set the marginValue = 20) and the right down corner is at (width-20,height-20). So if we want to be exactly inside the dotted area we need to set X and y like :

x = 20 + Math.random() * (width-20);
y = 20 + Math.random() * (height-20);

Unfortunately if we get 1.0(or close to 1.0) from the Math.random() that mean that the Start of the rectangle is going to be at x,y = (width-20,height-20) and the rectangle has a size of 20x20 so the rectangle ( or a part of it, depending of the value of the random()) will be outside of the dotted area. So we need to subtract from the width and height the actual rectangle size. Thus we need to have :

x = 20 + Math.random() * (width -20 - 20); // if we say the rect is 20x20
y = 20 + Math.random() * (height -20 - 20);

So our area is now the dotted one subtracted by dashed line.

JKostikiadis
  • 2,847
  • 2
  • 22
  • 34