Нужно расположить узел равномерно по всей площади

У меня есть следующий код, который перебирает список моих моделей и создает узлы в этой области.

        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()));
    }
}

Это выглядит следующим образом. Хочу равномерно распределить по всей площади. введите здесь описание изображения

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

это ключ здесь, который принимает положение узла x, y, но почему-то моя рандомизация не работает хорошо. Есть ли способ лучше.


person Saurabh Kumar    schedule 03.11.2017    source источник
comment
значения 50 и 300 являются фактическими размерами AnchroPane? Если нет, то в чем их смысл? Я бы ожидал что-то вроде: x.addAndGet(paddingValue + Math.random() * (paneWidth - paddingValue)); и то же самое для высоты, конечно.   -  person JKostikiadis    schedule 03.11.2017
comment
@JKostikiadis Спасибо за ответ. Это просто случайные числа, которые я выбрал. Не могли бы вы сказать мне, что такое paddingValue. Я предполагаю, что PaneWidth является родительской шириной anchorPane. Верно?   -  person Saurabh Kumar    schedule 03.11.2017
comment
Ну, я видел, что вы добавляете +10 с начала и -10 с конца. поэтому я предполагаю, что вы хотите иметь «заполнение» или, лучше, «маржу» внутри AnchorPane, где вы добавляете (перемещаете) свои узлы, в этом случае это значение является значением заполнения, которое я использовал. (Я просто использовал переменную для удаления эффекта Magic Number). Да, ширина панели должна быть фактической шириной AnchorPane, если вы хотите распределить узлы внутри AnchorPane. Конечно, вам придется сделать то же самое с высотой, например: y.addAndGet(paddingValue + Math.random() * (paneHeight - paddingValue));   -  person JKostikiadis    schedule 03.11.2017
comment
@JKostikiadis Я попробовал ваше предложение, но все же они расположены в виде змеи сверху вниз. Почему-то я чувствую, что случайная техника на самом деле не случайная, а инкрементная последовательность. Есть ли какая-нибудь библиотека для этого?   -  person Saurabh Kumar    schedule 03.11.2017
comment
Я публикую пример, который может быть вам полезен. Кроме того, я хотел бы увидеть метод addAndGet и то, как вы на самом деле обновляете значения x и y узлов внутри AnchorPane.   -  person JKostikiadis    schedule 03.11.2017
comment
AnchorPane размещает дочерние элементы на основе ограничения Saurabh не относительно точки   -  person Elltz    schedule 03.11.2017


Ответы (1)


Вот пример того, как вы можете перемещать свои узлы в случайных местах:

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);
        }
    }
}

Взгляните на randomizeLoc(), и я собираюсь добавить несколько изображений, объясняющих логику моих вычислений.

введите здесь описание изображения

Изменить: выше приведен пример AnchorPane. Фактические размеры — это заполненный прямоугольник, а область, которую мы хотим нарисовать, — это пунктирный прямоугольник. Теперь Math.random даст вам число от 0,0 до 1,0. Прежде всего, мы хотим быть уверены, что находимся внутри пунктирной области, так что верхний левый угол находится на (20,20) (если мы установим marginValue = 20), а правый нижний угол находится на (ширина-20, высота- 20). Итак, если мы хотим быть точно внутри пунктирной области, нам нужно установить X и y следующим образом:

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

К сожалению, если мы получаем 1.0 (или близко к 1.0) из Math.random(), это означает, что начало прямоугольника будет равно x, y = (width-20, height-20), а прямоугольник имеет размер размером 20x20, поэтому прямоугольник (или его часть, в зависимости от значения random()) будет находиться за пределами пунктирной области. Поэтому нам нужно вычесть из ширины и высоты фактический размер прямоугольника. Таким образом, нам нужно иметь:

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

Таким образом, наша область теперь представляет собой пунктирную область, вычитаемую из пунктирной линии.

person JKostikiadis    schedule 03.11.2017
comment
спасибо за хорошее объяснение. Я это попробую - person Saurabh Kumar; 03.11.2017